From 02bca1e6558bf4ac0cbf928d48e90f497b10b0a3 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 27 Oct 2024 18:11:15 +0100 Subject: Remove timings impl --- patches/api/0011-Timings-v2.patch | 62 +- ...-line-option-to-load-extra-plugin-jars-no.patch | 2 +- .../api/0015-Expose-server-build-information.patch | 13 +- .../api/0021-Add-exception-reporting-event.patch | 2 +- ...0182-Add-Raw-Byte-ItemStack-Serialization.patch | 4 +- ...Entity-Counter-to-allow-plugins-to-use-va.patch | 4 +- patches/api/0253-Expand-world-key-API.patch | 4 +- patches/api/0255-Expose-protocol-version.patch | 4 +- patches/api/0272-ItemStack-repair-check-API.patch | 4 +- .../api/0304-Get-entity-default-attributes.patch | 4 +- .../0312-Add-Raw-Byte-Entity-Serialization.patch | 4 +- .../api/0358-Add-NamespacedKey-biome-methods.patch | 4 +- ...02-Fix-custom-statistic-criteria-creation.patch | 4 +- ...0440-Add-api-for-spawn-egg-texture-colors.patch | 4 +- patches/api/0441-Add-Lifecycle-Event-system.patch | 4 +- patches/api/0442-ItemStack-Tooltip-API.patch | 4 +- patches/api/0472-Registry-Modification-API.patch | 4 +- .../0474-Proxy-ItemStack-to-CraftItemStack.patch | 4 +- patches/api/0485-Add-FeatureFlag-API.patch | 4 +- patches/api/0487-Item-serialization-as-json.patch | 4 +- patches/server/0005-Paper-config-files.patch | 29 +- patches/server/0009-MC-Utils.patch | 4 +- .../0023-Further-improve-server-tick-loop.patch | 233 + patches/server/0023-Timings-v2.patch | 2077 -- .../0024-Further-improve-server-tick-loop.patch | 233 - patches/server/0024-Remove-Spigot-timings.patch | 967 + ...-line-option-to-load-extra-plugin-jars-no.patch | 4 +- .../0033-Expose-server-build-information.patch | 30 +- patches/server/0036-Entity-Origin-API.patch | 4 +- ...7-Prevent-block-entity-and-entity-crashes.patch | 16 +- ...-entities-to-activation-range-ignore-list.patch | 4 +- patches/server/0043-Optimize-explosions.patch | 8 +- patches/server/0045-Disable-thunder.patch | 4 +- patches/server/0046-Disable-ice-and-snow.patch | 6 +- .../server/0052-Disable-spigot-tick-limiters.patch | 4 +- ...ix-spawn-location-event-changing-location.patch | 4 +- .../0055-Improve-Player-chat-API-handling.patch | 14 +- patches/server/0057-Expose-server-CommandMap.patch | 4 +- patches/server/0061-Add-velocity-warnings.patch | 2 +- .../0062-Add-exception-reporting-event.patch | 18 +- ...le-Scoreboards-for-non-players-by-default.patch | 4 +- ...lt-loading-permissions.yml-before-plugins.patch | 6 +- ...068-Allow-Reloading-of-Custom-Permissions.patch | 4 +- .../server/0069-Remove-Metadata-on-reload.patch | 4 +- patches/server/0072-Add-World-Util-Methods.patch | 4 +- .../0073-Custom-replacement-for-eaten-items.patch | 8 +- ...-health-absorb-values-and-repair-bad-data.patch | 8 +- ...gurable-spawn-chances-for-skeleton-horses.patch | 4 +- ...s-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch | 12 +- ...0078-Entity-AddTo-RemoveFrom-World-Events.patch | 6 +- .../0079-Configurable-Chunk-Inhabited-Time.patch | 2 +- .../0083-Add-PlayerUseUnknownEntityEvent.patch | 4 +- ...elling-BlockPlaceEvent-triggering-physics.patch | 4 +- .../0088-Configurable-Player-Collision.patch | 14 +- ...1-EntityRegainHealthEvent-isFastRegen-API.patch | 4 +- ...-null-possibility-for-getServer-singleton.patch | 8 +- .../0097-Async-GameProfileCache-saving.patch | 8 +- ...Faster-redstone-torch-rapid-clock-removal.patch | 4 +- .../server/0101-Fix-global-sound-handling.patch | 6 +- ...-Add-setting-for-proxy-online-mode-status.patch | 8 +- ...106-Configurable-packet-in-spam-threshold.patch | 2 +- .../0107-Configurable-flying-kick-messages.patch | 2 +- .../0111-Allow-Reloading-of-Command-Aliases.patch | 4 +- ...Optimize-Level.hasChunkAt-BlockPosition-Z.patch | 4 +- ...123-Provide-E-TE-Chunk-count-stat-methods.patch | 2 +- .../server/0124-Enforce-Sync-Player-Saves.patch | 10 +- ...rbs-API-for-Reason-Source-Triggering-play.patch | 8 +- patches/server/0126-Cap-Entity-Collisions.patch | 4 +- ...Remove-CraftScheduler-Async-Task-Debugger.patch | 10 +- ...-handle-async-calls-to-restart-the-server.patch | 12 +- ...to-make-parrots-stay-on-shoulders-despite.patch | 4 +- ...ration-option-to-prevent-player-names-fro.patch | 4 +- patches/server/0136-Basic-PlayerProfile-API.patch | 4 +- patches/server/0137-Add-UnknownCommandEvent.patch | 4 +- .../server/0145-ProfileWhitelistVerifyEvent.patch | 6 +- patches/server/0151-Add-PlayerJumpEvent.patch | 2 +- .../server/0156-Add-PlayerArmorChangeEvent.patch | 4 +- ...x-MC-117075-Block-entity-unload-lag-spike.patch | 8 +- ...kState-implementations-for-captured-block.patch | 8 +- ...PI-to-get-a-BlockState-without-a-snapshot.patch | 8 +- patches/server/0161-AsyncTabCompleteEvent.patch | 6 +- .../0164-PlayerNaturallySpawnCreaturesEvent.patch | 10 +- patches/server/0166-PreCreatureSpawnEvent.patch | 10 +- ...plement-extended-PaperServerListPingEvent.patch | 4 +- .../server/0176-Player.setPlayerProfile-API.patch | 4 +- patches/server/0177-getPlayerUniqueId-API.patch | 4 +- .../0178-Improved-Async-Task-Scheduler.patch | 43 +- ...d-World.spawnParticle-API-and-add-Builder.patch | 4 +- ...8-Make-shield-blocking-delay-configurable.patch | 4 +- .../server/0201-Add-entity-knockback-events.patch | 10 +- patches/server/0202-Expand-Explosions-API.patch | 6 +- .../0207-InventoryCloseEvent-Reason-API.patch | 14 +- ...revent-armor-stands-from-doing-entity-loo.patch | 4 +- .../0215-Vanished-players-don-t-have-rights.patch | 4 +- ...-up-and-make-tab-spam-limits-configurable.patch | 2 +- ...Entities-option-to-debug-dupe-uuid-issues.patch | 4 +- ...225-Add-Early-Warning-Feature-to-WatchDog.patch | 14 +- .../0226-Use-ConcurrentHashMap-in-JsonList.patch | 4 +- .../0227-Use-a-Queue-for-Queueing-Commands.patch | 7 +- ...9-Add-ray-tracing-methods-to-LivingEntity.patch | 4 +- patches/server/0241-Improve-death-events.patch | 14 +- ...b-spawning-from-loading-generating-chunks.patch | 6 +- .../0251-Add-LivingEntity-getTargetEntity.patch | 4 +- ...to-prevent-players-from-moving-into-unloa.patch | 2 +- ...-Server-Thread-Pool-and-Thread-Priorities.patch | 4 +- .../server/0261-Optimize-World-Time-Updates.patch | 10 +- ...-Don-t-allow-digging-into-unloaded-chunks.patch | 2 +- ...e-default-permission-message-configurable.patch | 4 +- ...orce-entity-dismount-during-teleportation.patch | 4 +- patches/server/0268-Book-size-limits.patch | 2 +- .../0270-Replace-OfflinePlayer-getLastPlayed.patch | 4 +- patches/server/0273-BlockDestroyEvent.patch | 4 +- .../server/0274-Async-command-map-building.patch | 6 +- patches/server/0275-Brigadier-Mojang-API.patch | 2 +- .../0276-Limit-Client-Sign-length-more.patch | 4 +- ...listToggleEvent-when-whitelist-is-toggled.patch | 4 +- ...xes-and-additions-to-the-spawn-reason-API.patch | 12 +- .../server/0280-Add-PlayerPostRespawnEvent.patch | 10 +- patches/server/0281-Server-Tick-Events.patch | 20 +- ...0283-Optimize-Captured-BlockEntity-Lookup.patch | 4 +- .../0288-Expose-the-internal-current-tick.patch | 4 +- ...Natural-Spawned-mobs-towards-natural-spaw.patch | 2 +- ...293-Prevent-consuming-the-wrong-itemstack.patch | 8 +- ...301-Optimise-EntityGetter-getPlayerByUUID.patch | 4 +- .../0302-Fix-items-not-falling-correctly.patch | 4 +- .../server/0306-Tracking-Range-Improvements.patch | 4 +- ...timise-getChunkAt-calls-for-loaded-chunks.patch | 4 +- .../0310-Add-debug-for-sync-chunk-loads.patch | 14 +- patches/server/0313-Entity-Jump-API.patch | 4 +- patches/server/0320-Optimise-Chunk-getFluid.patch | 2 +- .../0322-Add-tick-times-API-and-mspt-command.patch | 14 +- .../0323-Expose-MinecraftServer-isRunning.patch | 4 +- ...0324-Add-Raw-Byte-ItemStack-Serialization.patch | 6 +- ...te-Connections-shouldn-t-hold-up-shutdown.patch | 4 +- ...ouble-PlayerChunkMap-adds-crashing-server.patch | 10 +- ...on-t-move-existing-players-to-world-spawn.patch | 4 +- ...t-run-entity-collision-code-if-not-needed.patch | 4 +- ...erJoinEvent-when-Player-is-actually-ready.patch | 12 +- ...-to-spawn-point-if-spawn-in-unloaded-worl.patch | 8 +- ...-Add-PlayerAttackEntityCooldownResetEvent.patch | 4 +- ...-Fix-item-duplication-and-teleport-issues.patch | 6 +- ...date-PickItem-Packet-and-kick-for-invalid.patch | 2 +- patches/server/0348-misc-debugging-dumps.patch | 12 +- .../0349-Prevent-teleporting-dead-entities.patch | 2 +- patches/server/0350-Implement-Mob-Goal-API.patch | 4 +- ...0355-Wait-for-Async-Tasks-during-shutdown.patch | 8 +- ...heduler-runTaskTimerAsynchronously-Plugin.patch | 4 +- ...revent-position-desync-causing-tp-exploit.patch | 2 +- .../0366-Add-PlayerRecipeBookClickEvent.patch | 4 +- .../0368-Add-permission-for-command-blocks.patch | 2 +- ...r-World-Difficulty-Remembering-Difficulty.patch | 20 +- ...3-Add-Plugin-Tickets-to-API-Chunk-Methods.patch | 6 +- ...376-Do-not-accept-invalid-client-settings.patch | 4 +- ...-chunk-for-portal-on-world-gen-entity-add.patch | 4 +- ...nChangeEvent-not-firing-for-all-use-cases.patch | 4 +- patches/server/0403-Cache-block-data-strings.patch | 4 +- ...Teleportation-and-cancel-velocity-if-tele.patch | 2 +- ...k-drop-capture-to-capture-all-items-added.patch | 4 +- ...Entity-Counter-to-allow-plugins-to-use-va.patch | 6 +- ...cking-non-whitelisted-player-when-white-l.patch | 4 +- ...ix-for-large-move-vectors-crashing-server.patch | 2 +- ...ck-place-order-when-capturing-blockstates.patch | 2 +- .../0421-Add-getOfflinePlayerIfCached-String.patch | 4 +- ...424-Fix-client-lag-on-advancement-loading.patch | 4 +- patches/server/0427-Add-API-for-quit-reason.patch | 4 +- ...mbing-should-not-bypass-cramming-gamerule.patch | 6 +- patches/server/0438-Limit-recipe-packets.patch | 4 +- ...interact-event-not-being-called-sometimes.patch | 4 +- .../0457-Add-ServerResourcesReloadedEvent.patch | 6 +- patches/server/0464-Remove-stale-POIs.patch | 4 +- .../server/0465-Fix-villager-boat-exploit.patch | 4 +- patches/server/0466-Add-sendOpLevel-API.patch | 6 +- ...dd-RegistryAccess-for-managing-Registries.patch | 6 +- patches/server/0480-Add-EntityMoveEvent.patch | 12 +- ...n-to-disable-pathfinding-updates-on-block.patch | 6 +- ...-getMainThreadExecutor-to-BukkitScheduler.patch | 4 +- .../0490-fix-converting-txt-to-json-file.patch | 10 +- ...Allow-using-signs-inside-spawn-protection.patch | 2 +- patches/server/0496-Expand-world-key-API.patch | 14 +- ...carried-item-when-player-has-disconnected.patch | 4 +- ...d-whitelist-use-configurable-kick-message.patch | 4 +- ...on-t-ignore-result-of-PlayerEditBookEvent.patch | 2 +- patches/server/0501-Expose-protocol-version.patch | 6 +- ...sole-tab-completions-for-brigadier-comman.patch | 6 +- ...layerItemConsumeEvent-cancelling-properly.patch | 4 +- ...0510-fix-PlayerItemHeldEvent-firing-twice.patch | 2 +- ...ethods-to-convert-between-Component-and-B.patch | 4 +- patches/server/0525-Add-basic-Datapack-API.patch | 6 +- .../0527-Expand-PlayerGameModeChangeEvent.patch | 4 +- .../server/0528-ItemStack-repair-check-API.patch | 6 +- ...530-Move-range-check-for-block-placing-up.patch | 2 +- .../0533-Add-Unix-domain-socket-support.patch | 10 +- .../0535-Improve-item-default-attribute-API.patch | 4 +- ...-Add-cause-to-Weather-ThunderChangeEvents.patch | 8 +- .../server/0539-Add-PlayerKickEvent-causes.patch | 28 +- patches/server/0548-Line-Of-Sight-Changes.patch | 4 +- ...Use-getChunkIfLoadedImmediately-in-places.patch | 8 +- patches/server/0557-Add-PlayerArmSwingEvent.patch | 4 +- ...x-kick-event-leave-message-not-being-sent.patch | 6 +- ...ons-and-timings-for-sensors-and-behaviors.patch | 61 +- .../server/0563-Add-System.out-err-catcher.patch | 2 +- ...event-AFK-kick-while-watching-end-credits.patch | 2 +- patches/server/0566-Add-PlayerSetSpawnEvent.patch | 4 +- patches/server/0574-Add-BlockBreakBlockEvent.patch | 4 +- ...ods-to-find-targets-for-lightning-strikes.patch | 6 +- .../0580-Get-entity-default-attributes.patch | 6 +- .../0589-Add-Raw-Byte-Entity-Serialization.patch | 4 +- ...close-logic-for-inventories-on-chunk-unlo.patch | 4 +- .../0593-Improve-and-expand-AsyncCatcher.patch | 6 +- ...Add-paper-mobcaps-and-paper-playermobcaps.patch | 8 +- ...nlined-getChunkAt-has-inlined-logic-for-l.patch | 4 +- ...601-Oprimise-map-impl-for-tracked-players.patch | 21 + patches/server/0601-Time-scoreboard-search.patch | 43 - .../server/0602-Add-missing-InventoryType.patch | 22 + ...602-Oprimise-map-impl-for-tracked-players.patch | 21 - .../server/0603-Add-missing-InventoryType.patch | 22 - ...03-Optimise-BlockSoil-nearby-water-lookup.patch | 52 + ...t-inventory-not-closing-on-entity-removal.patch | 22 + ...04-Optimise-BlockSoil-nearby-water-lookup.patch | 52 - ...-requirement-before-suggesting-root-nodes.patch | 32 + ...t-inventory-not-closing-on-entity-removal.patch | 22 - ...-requirement-before-suggesting-root-nodes.patch | 32 - ...nd-to-ServerboundCommandSuggestionPacket-.patch | 23 + .../server/0607-Add-packet-limiter-config.patch | 108 + ...nd-to-ServerboundCommandSuggestionPacket-.patch | 23 - .../server/0608-Add-packet-limiter-config.patch | 108 - ...PatternColor-on-tropical-fish-bucket-meta.patch | 72 + .../server/0609-Ensure-valid-vehicle-status.patch | 19 + ...PatternColor-on-tropical-fish-bucket-meta.patch | 72 - .../server/0610-Ensure-valid-vehicle-status.patch | 19 - ...ent-softlocked-end-exit-portal-generation.patch | 22 + ...corator-causing-a-crash-when-trying-to-ge.patch | 19 + ...ent-softlocked-end-exit-portal-generation.patch | 22 - ...12-Don-t-log-debug-logging-being-disabled.patch | 19 + ...corator-causing-a-crash-when-trying-to-ge.patch | 19 - ...13-Don-t-log-debug-logging-being-disabled.patch | 19 - ...x-various-menus-with-empty-level-accesses.patch | 23 + .../server/0614-Preserve-overstacked-loot.patch | 27 + ...x-various-menus-with-empty-level-accesses.patch | 23 - .../server/0615-Preserve-overstacked-loot.patch | 27 - ...15-Update-head-rotation-in-missing-places.patch | 29 + ...16-Update-head-rotation-in-missing-places.patch | 29 - ...event-unintended-light-block-manipulation.patch | 25 + .../0617-Fix-CraftCriteria-defaults-map.patch | 19 + ...event-unintended-light-block-manipulation.patch | 25 - .../0618-Fix-CraftCriteria-defaults-map.patch | 19 - .../0618-Fix-upstreams-block-state-factories.patch | 491 + .../server/0619-Configurable-feature-seeds.patch | 27 + .../0619-Fix-upstreams-block-state-factories.patch | 491 - .../0620-Add-root-admin-user-detection.patch | 62 + .../server/0620-Configurable-feature-seeds.patch | 40 - .../0621-Add-root-admin-user-detection.patch | 62 - ...1-don-t-attempt-to-teleport-dead-entities.patch | 19 + ...excessive-velocity-through-repeated-crits.patch | 41 + ...2-don-t-attempt-to-teleport-dead-entities.patch | 19 - ...excessive-velocity-through-repeated-crits.patch | 41 - ...nt-side-code-using-deprecated-for-removal.patch | 30 + .../server/0624-Fix-Spigot-growth-modifiers.patch | 141 + ...nt-side-code-using-deprecated-for-removal.patch | 30 - .../server/0625-Fix-Spigot-growth-modifiers.patch | 141 - ...tainerOpenersCounter-openCount-from-going.patch | 18 + .../0626-Add-PlayerItemFrameChangeEvent.patch | 61 + ...tainerOpenersCounter-openCount-from-going.patch | 18 - .../0627-Add-PlayerItemFrameChangeEvent.patch | 61 - patches/server/0627-Optimize-HashMapPalette.patch | 57 + ...apshot-isSectionEmpty-int-and-optimize-Pa.patch | 44 + patches/server/0628-Optimize-HashMapPalette.patch | 57 - patches/server/0629-Add-more-Campfire-API.patch | 111 + ...apshot-isSectionEmpty-int-and-optimize-Pa.patch | 44 - patches/server/0630-Add-more-Campfire-API.patch | 111 - ...chunk-data-to-disk-if-it-serializes-witho.patch | 94 + ...1-Forward-CraftEntity-in-teleport-command.patch | 35 + ...chunk-data-to-disk-if-it-serializes-witho.patch | 94 - ...2-Forward-CraftEntity-in-teleport-command.patch | 35 - .../server/0632-Improve-scoreboard-entries.patch | 88 + patches/server/0633-Entity-powdered-snow-API.patch | 42 + .../server/0633-Improve-scoreboard-entries.patch | 88 - .../0634-Add-API-for-item-entity-health.patch | 34 + patches/server/0634-Entity-powdered-snow-API.patch | 42 - .../0635-Add-API-for-item-entity-health.patch | 34 - ...able-max-block-light-for-monster-spawning.patch | 19 + ...able-max-block-light-for-monster-spawning.patch | 19 - ...ticky-pistons-and-BlockPistonRetractEvent.patch | 85 + ...el-and-canSmelt-methods-to-FurnaceInvento.patch | 32 + ...ticky-pistons-and-BlockPistonRetractEvent.patch | 85 - patches/server/0638-Bucketable-API.patch | 69 + ...el-and-canSmelt-methods-to-FurnaceInvento.patch | 32 - patches/server/0639-Bucketable-API.patch | 69 - patches/server/0639-Validate-usernames.patch | 76 + ...ke-water-animal-spawn-height-configurable.patch | 21 + patches/server/0640-Validate-usernames.patch | 76 - ...pose-vanilla-BiomeProvider-from-WorldInfo.patch | 177 + ...ke-water-animal-spawn-height-configurable.patch | 21 - ...ig-option-for-worlds-affected-by-time-cmd.patch | 28 + ...pose-vanilla-BiomeProvider-from-WorldInfo.patch | 177 - ...ig-option-for-worlds-affected-by-time-cmd.patch | 28 - ...-IAE-check-for-PersistentDataContainer-ha.patch | 18 + ...-IAE-check-for-PersistentDataContainer-ha.patch | 18 - .../0644-Multiple-Entries-with-Scoreboards.patch | 125 + .../0645-Multiple-Entries-with-Scoreboards.patch | 125 - .../0645-Reset-placed-block-on-exception.patch | 39 + ...6-Add-configurable-height-for-slime-spawn.patch | 35 + .../0646-Reset-placed-block-on-exception.patch | 39 - ...7-Add-configurable-height-for-slime-spawn.patch | 35 - .../0647-Fix-xp-reward-for-baby-zombies.patch | 32 + .../0648-Fix-xp-reward-for-baby-zombies.patch | 32 - ...648-Multi-Block-Change-API-Implementation.patch | 62 + patches/server/0649-Fix-NotePlayEvent.patch | 54 + ...649-Multi-Block-Change-API-Implementation.patch | 62 - patches/server/0650-Fix-NotePlayEvent.patch | 54 - patches/server/0650-Freeze-Tick-Lock-API.patch | 82 + patches/server/0651-Freeze-Tick-Lock-API.patch | 82 - .../server/0651-More-PotionEffectType-API.patch | 98 + .../server/0652-More-PotionEffectType-API.patch | 98 - ...a-CHM-for-StructureTemplate.Pallete-cache.patch | 20 + ...ating-command-sender-which-forwards-feedb.patch | 170 + ...a-CHM-for-StructureTemplate.Pallete-cache.patch | 20 - ...ating-command-sender-which-forwards-feedb.patch | 170 - ...54-Add-missing-structure-set-seed-configs.patch | 399 + ...55-Add-missing-structure-set-seed-configs.patch | 399 - ...-cancelled-powdered-snow-bucket-placement.patch | 31 + ...-Validate-calls-to-CraftServer-getSpawnLi.patch | 20 + ...-cancelled-powdered-snow-bucket-placement.patch | 31 - patches/server/0657-Add-GameEvent-tags.patch | 81 + ...-Validate-calls-to-CraftServer-getSpawnLi.patch | 20 - patches/server/0658-Add-GameEvent-tags.patch | 81 - ...nk-tasks-fairly-for-worlds-while-waiting-.patch | 37 + ...nk-tasks-fairly-for-worlds-while-waiting-.patch | 37 - patches/server/0659-Furnace-RecipesUsed-API.patch | 48 + ...-Configurable-sculk-sensor-listener-range.patch | 106 + patches/server/0660-Furnace-RecipesUsed-API.patch | 48 - .../server/0661-Add-missing-block-data-API.patch | 214 + ...-Configurable-sculk-sensor-listener-range.patch | 106 - .../server/0662-Add-missing-block-data-API.patch | 214 - ...ave-default-CustomSpawners-in-custom-worl.patch | 32 + ...ave-default-CustomSpawners-in-custom-worl.patch | 32 - ...d-into-worldlist-before-initing-the-world.patch | 41 + patches/server/0664-Custom-Potion-Mixes.patch | 329 + ...d-into-worldlist-before-initing-the-world.patch | 41 - patches/server/0665-Custom-Potion-Mixes.patch | 329 - .../0665-Force-close-world-loading-screen.patch | 32 + .../0666-Fix-falling-block-spawn-methods.patch | 57 + .../0666-Force-close-world-loading-screen.patch | 32 - .../0667-Expose-furnace-minecart-push-values.patch | 42 + .../0667-Fix-falling-block-spawn-methods.patch | 57 - .../0668-Expose-furnace-minecart-push-values.patch | 42 - ...ing-ProjectileHitEvent-for-piercing-arrow.patch | 40 + ...ing-ProjectileHitEvent-for-piercing-arrow.patch | 40 - patches/server/0669-More-Projectile-API.patch | 932 + ...670-Fix-swamp-hut-cat-generation-deadlock.patch | 64 + patches/server/0670-More-Projectile-API.patch | 932 - ...-vehicle-movement-from-players-while-tele.patch | 24 + ...671-Fix-swamp-hut-cat-generation-deadlock.patch | 64 - ...-vehicle-movement-from-players-while-tele.patch | 24 - .../0672-Implement-getComputedBiome-API.patch | 61 + .../0673-Implement-getComputedBiome-API.patch | 61 - .../server/0673-Make-some-itemstacks-nonnull.patch | 28 + .../0674-Implement-enchantWithLevels-API.patch | 58 + .../server/0674-Make-some-itemstacks-nonnull.patch | 28 - .../server/0675-Fix-saving-in-unloadWorld.patch | 20 + .../0675-Implement-enchantWithLevels-API.patch | 58 - .../server/0676-Buffer-OOB-setBlock-calls.patch | 42 + .../server/0676-Fix-saving-in-unloadWorld.patch | 20 - .../0677-Add-TameableDeathMessageEvent.patch | 24 + .../server/0677-Buffer-OOB-setBlock-calls.patch | 42 - .../0678-Add-TameableDeathMessageEvent.patch | 24 - ...new-block-data-for-EntityChangeBlockEvent.patch | 215 + ...new-block-data-for-EntityChangeBlockEvent.patch | 215 - ...loottables-running-when-mob-loot-gamerule.patch | 25 + ...ity-passenger-world-matches-ridden-entity.patch | 20 + ...loottables-running-when-mob-loot-gamerule.patch | 25 - ...rce-keys-and-optimize-reference-Holder-ta.patch | 66 + ...ity-passenger-world-matches-ridden-entity.patch | 20 - ...682-Allow-changing-the-EnderDragon-podium.patch | 142 + ...rce-keys-and-optimize-reference-Holder-ta.patch | 66 - ...683-Allow-changing-the-EnderDragon-podium.patch | 142 - ...ces-overriding-a-block-entity-during-worl.patch | 40 + ...ces-overriding-a-block-entity-during-worl.patch | 40 - ...Prevent-tile-entity-copies-loading-chunks.patch | 24 + ...Prevent-tile-entity-copies-loading-chunks.patch | 24 - ...e-instead-of-display-name-in-PlayerList-g.patch | 20 + .../server/0686-Expand-PlayerItemDamageEvent.patch | 23 + ...e-instead-of-display-name-in-PlayerList-g.patch | 20 - .../server/0687-Expand-PlayerItemDamageEvent.patch | 23 - .../server/0687-WorldCreator-keepSpawnLoaded.patch | 19 + ...ix-CME-in-CraftPersistentDataTypeRegistry.patch | 19 + .../server/0688-WorldCreator-keepSpawnLoaded.patch | 19 - ...ix-CME-in-CraftPersistentDataTypeRegistry.patch | 19 - ..._nest_destroyed-trigger-in-the-correct-pl.patch | 54 + ...ityDyeEvent-and-CollarColorable-interface.patch | 43 + ..._nest_destroyed-trigger-in-the-correct-pl.patch | 54 - ...ityDyeEvent-and-CollarColorable-interface.patch | 43 - ...-Fire-CauldronLevelChange-on-initial-fill.patch | 122 + ...-Fire-CauldronLevelChange-on-initial-fill.patch | 122 - ...owder-snow-cauldrons-not-turning-to-water.patch | 45 + .../server/0693-Add-PlayerStopUsingItemEvent.patch | 18 + ...owder-snow-cauldrons-not-turning-to-water.patch | 45 - .../server/0694-Add-PlayerStopUsingItemEvent.patch | 18 - patches/server/0694-Don-t-tick-markers.patch | 36 + patches/server/0695-Don-t-tick-markers.patch | 36 - patches/server/0695-Expand-FallingBlock-API.patch | 107 + .../0696-Add-support-for-Proxy-Protocol.patch | 65 + patches/server/0696-Expand-FallingBlock-API.patch | 107 - .../0697-Add-support-for-Proxy-Protocol.patch | 65 - ...697-Fix-OfflinePlayer-getBedSpawnLocation.patch | 46 + ...eInventory-for-smokers-and-blast-furnaces.patch | 49 + ...698-Fix-OfflinePlayer-getBedSpawnLocation.patch | 46 - ...eInventory-for-smokers-and-blast-furnaces.patch | 49 - .../0699-Sanitize-sent-BlockEntity-NBT.patch | 50 + ...ponent-selector-resolving-in-books-by-def.patch | 19 + .../0700-Sanitize-sent-BlockEntity-NBT.patch | 50 - ...ponent-selector-resolving-in-books-by-def.patch | 19 - ...vent-entity-loading-causing-async-lookups.patch | 81 + ...vent-entity-loading-causing-async-lookups.patch | 81 - ...eption-on-world-create-while-being-ticked.patch | 78 + .../0703-Dont-resent-entity-on-art-update.patch | 19 + ...eption-on-world-create-while-being-ticked.patch | 78 - .../server/0704-Add-WardenAngerChangeEvent.patch | 39 + .../0704-Dont-resent-entity-on-art-update.patch | 19 - .../server/0705-Add-WardenAngerChangeEvent.patch | 39 - ...n-for-strict-advancement-dimension-checks.patch | 42 + ...-important-BlockStateListPopulator-method.patch | 73 + ...n-for-strict-advancement-dimension-checks.patch | 42 - ...-important-BlockStateListPopulator-method.patch | 73 - patches/server/0707-Nameable-Banner-API.patch | 50 + ...on-t-broadcast-messages-to-command-blocks.patch | 34 + patches/server/0708-Nameable-Banner-API.patch | 50 - ...on-t-broadcast-messages-to-command-blocks.patch | 34 - ...ent-empty-items-from-being-added-to-world.patch | 20 + ...-SplashPotion-and-LingeringPotion-spawnin.patch | 21 + ...ent-empty-items-from-being-added-to-world.patch | 20 - patches/server/0711-Add-Player-getFishHook.patch | 26 + ...-SplashPotion-and-LingeringPotion-spawnin.patch | 21 - patches/server/0712-Add-Player-getFishHook.patch | 26 - ...-load-chunk-for-dynamic-game-event-listen.patch | 29 + ...various-missing-EntityDropItemEvent-calls.patch | 109 + ...-load-chunk-for-dynamic-game-event-listen.patch | 29 - ...various-missing-EntityDropItemEvent-calls.patch | 109 - patches/server/0714-Fix-Bee-flower-NPE.patch | 19 + patches/server/0715-Fix-Bee-flower-NPE.patch | 19 - patches/server/0715-More-Teleport-API.patch | 272 + .../server/0716-Add-EntityPortalReadyEvent.patch | 25 + patches/server/0716-More-Teleport-API.patch | 272 - .../server/0717-Add-EntityPortalReadyEvent.patch | 25 - ...t-use-level-random-in-entity-constructors.patch | 41 + ...t-use-level-random-in-entity-constructors.patch | 41 - ...d-block-entities-after-destroy-prediction.patch | 91 + ...d-block-entities-after-destroy-prediction.patch | 91 - ...-Warn-on-plugins-accessing-faraway-chunks.patch | 96 + ...20-Custom-Chat-Completion-Suggestions-API.patch | 35 + ...-Warn-on-plugins-accessing-faraway-chunks.patch | 96 - .../0721-Add-and-fix-missing-BlockFadeEvents.patch | 71 + ...21-Custom-Chat-Completion-Suggestions-API.patch | 35 - .../0722-Add-and-fix-missing-BlockFadeEvents.patch | 71 - patches/server/0722-Collision-API.patch | 48 + patches/server/0723-Collision-API.patch | 48 - ...-command-message-for-brigadier-syntax-exc.patch | 20 + patches/server/0724-Block-Ticking-API.patch | 63 + ...-command-message-for-brigadier-syntax-exc.patch | 20 - .../0725-Add-Velocity-IP-Forwarding-Support.patch | 242 + patches/server/0725-Block-Ticking-API.patch | 63 - .../0726-Add-NamespacedKey-biome-methods.patch | 31 + .../0726-Add-Velocity-IP-Forwarding-Support.patch | 242 - .../0727-Add-NamespacedKey-biome-methods.patch | 33 - ...727-Fix-plugin-loggers-on-server-shutdown.patch | 67 + ...728-Fix-plugin-loggers-on-server-shutdown.patch | 67 - ...rge-look-changes-from-crashing-the-server.patch | 74 + ...ire-EntityChangeBlockEvent-in-more-places.patch | 344 + ...rge-look-changes-from-crashing-the-server.patch | 74 - ...ire-EntityChangeBlockEvent-in-more-places.patch | 344 - .../server/0730-Missing-eating-regain-reason.patch | 45 + .../server/0731-Missing-eating-regain-reason.patch | 45 - patches/server/0731-Missing-effect-cause.patch | 19 + ...array-serialization-deserialization-for-P.patch | 39 + patches/server/0732-Missing-effect-cause.patch | 19 - ...array-serialization-deserialization-for-P.patch | 39 - .../0733-Call-BlockPhysicsEvent-more-often.patch | 32 + .../0734-Call-BlockPhysicsEvent-more-often.patch | 32 - .../0734-Configurable-chat-thread-limit.patch | 47 + .../0735-Configurable-chat-thread-limit.patch | 47 - ...fects-of-WorldCreator-keepSpawnLoaded-ret.patch | 25 + ...fects-of-WorldCreator-keepSpawnLoaded-ret.patch | 25 - .../0736-fix-Jigsaw-block-kicking-user.patch | 24 + .../0737-fix-Jigsaw-block-kicking-user.patch | 24 - ...ockFormEvent-for-mud-converting-into-clay.patch | 25 + .../server/0738-Add-getDrops-to-BlockState.patch | 37 + ...ockFormEvent-for-mud-converting-into-clay.patch | 25 - .../server/0739-Add-getDrops-to-BlockState.patch | 37 - .../server/0739-Fix-a-bunch-of-vanilla-bugs.patch | 394 + .../server/0740-Fix-a-bunch-of-vanilla-bugs.patch | 394 - ...cessary-onTrackingStart-during-navigation.patch | 28 + .../0741-Fix-custom-piglin-loved-items.patch | 21 + ...cessary-onTrackingStart-during-navigation.patch | 28 - .../server/0742-EntityPickupItemEvent-fixes.patch | 73 + .../0742-Fix-custom-piglin-loved-items.patch | 21 - ...andle-interactions-with-items-on-cooldown.patch | 60 + .../server/0743-EntityPickupItemEvent-fixes.patch | 73 - .../0744-Add-PlayerInventorySlotChangeEvent.patch | 65 + ...andle-interactions-with-items-on-cooldown.patch | 60 - .../0745-Add-PlayerInventorySlotChangeEvent.patch | 65 - .../0745-Elder-Guardian-appearance-API.patch | 24 + patches/server/0746-Add-entity-knockback-API.patch | 23 + .../0746-Elder-Guardian-appearance-API.patch | 24 - patches/server/0747-Add-entity-knockback-API.patch | 23 - patches/server/0747-Detect-headless-JREs.patch | 51 + patches/server/0748-Detect-headless-JREs.patch | 51 - ...entity-vehicle-collision-event-not-called.patch | 27 + patches/server/0749-Add-EntityToggleSitEvent.patch | 100 + ...entity-vehicle-collision-event-not-called.patch | 27 - patches/server/0750-Add-EntityToggleSitEvent.patch | 100 - .../server/0750-Add-fire-tick-delay-option.patch | 34 + patches/server/0751-Add-Moving-Piston-API.patch | 46 + .../server/0751-Add-fire-tick-delay-option.patch | 34 - patches/server/0752-Add-Moving-Piston-API.patch | 46 - .../server/0752-Ignore-impossible-spawn-tick.patch | 18 + ...rgument-and-EntitySelectorParser-permissi.patch | 41 + .../server/0753-Ignore-impossible-spawn-tick.patch | 18 - ...rgument-and-EntitySelectorParser-permissi.patch | 41 - ...ombustEvent-cancellation-cant-fully-preve.patch | 37 + .../0755-Add-PrePlayerAttackEntityEvent.patch | 30 + ...ombustEvent-cancellation-cant-fully-preve.patch | 37 - .../0756-Add-PrePlayerAttackEntityEvent.patch | 30 - ...-ensure-reset-EnderDragon-boss-event-name.patch | 39 + .../0757-Add-Player-Warden-Warning-API.patch | 57 + ...-ensure-reset-EnderDragon-boss-event-name.patch | 39 - .../0758-Add-Player-Warden-Warning-API.patch | 57 - ...vanilla-friendly-methods-to-update-trades.patch | 75 + .../0759-Add-paper-dumplisteners-command.patch | 197 + ...vanilla-friendly-methods-to-update-trades.patch | 75 - .../0760-Add-paper-dumplisteners-command.patch | 197 - ...heck-global-player-list-where-appropriate.patch | 85 + ...-Fix-async-entity-add-due-to-fungus-trees.patch | 35 + ...heck-global-player-list-where-appropriate.patch | 85 - ...-Fix-async-entity-add-due-to-fungus-trees.patch | 35 - patches/server/0762-ItemStack-damage-API.patch | 121 + patches/server/0763-Friction-API.patch | 156 + patches/server/0763-ItemStack-damage-API.patch | 121 - ...to-control-player-s-insomnia-and-phantoms.patch | 67 + patches/server/0764-Friction-API.patch | 156 - ...to-control-player-s-insomnia-and-phantoms.patch | 67 - ...65-Fix-premature-player-kicks-on-shutdown.patch | 61 + ...66-Fix-premature-player-kicks-on-shutdown.patch | 61 - .../server/0766-Sync-offhand-slot-in-menus.patch | 51 + .../0767-Player-Entity-Tracking-Events.patch | 42 + .../server/0767-Sync-offhand-slot-in-menus.patch | 51 - patches/server/0768-Limit-pet-look-distance.patch | 19 + .../0768-Player-Entity-Tracking-Events.patch | 42 - patches/server/0769-Limit-pet-look-distance.patch | 19 - patches/server/0769-fix-Instruments.patch | 57 + ...ining-for-some-hot-BlockBehavior-and-Flui.patch | 78 + patches/server/0770-fix-Instruments.patch | 57 - patches/server/0771-Add-BlockLockCheckEvent.patch | 70 + ...ining-for-some-hot-BlockBehavior-and-Flui.patch | 78 - patches/server/0772-Add-BlockLockCheckEvent.patch | 70 - .../0772-Add-Sneaking-API-for-Entities.patch | 29 + .../0773-Add-Sneaking-API-for-Entities.patch | 29 - .../server/0773-Improve-logging-and-errors.patch | 104 + patches/server/0774-Improve-PortalEvents.patch | 103 + .../server/0774-Improve-logging-and-errors.patch | 104 - ...ig-option-for-spider-worldborder-climbing.patch | 19 + patches/server/0775-Improve-PortalEvents.patch | 103 - ...ig-option-for-spider-worldborder-climbing.patch | 19 - ...dd-missing-SpigotConfig-logCommands-check.patch | 31 + ...dd-missing-SpigotConfig-logCommands-check.patch | 31 - ...PE-on-Allay-stopDancing-while-not-dancing.patch | 19 + ...PE-on-Allay-stopDancing-while-not-dancing.patch | 19 - patches/server/0778-Flying-Fall-Damage.patch | 51 + ...collision-moving-velocity-to-VehicleBlock.patch | 28 + patches/server/0779-Flying-Fall-Damage.patch | 51 - ...collision-moving-velocity-to-VehicleBlock.patch | 28 - ...0780-config-for-disabling-entity-tag-tags.patch | 27 + ...-single-player-info-update-packet-on-join.patch | 51 + ...0781-config-for-disabling-entity-tag-tags.patch | 27 - ...-shrink-items-during-EntityResurrectEvent.patch | 36 + ...-single-player-info-update-packet-on-join.patch | 51 - ...-shrink-items-during-EntityResurrectEvent.patch | 36 - patches/server/0783-Win-Screen-API.patch | 38 + ...-CraftItemStack-setAmount-null-assignment.patch | 30 + patches/server/0784-Win-Screen-API.patch | 38 - ...0785-Fix-force-opening-enchantment-tables.patch | 30 + ...-CraftItemStack-setAmount-null-assignment.patch | 30 - patches/server/0786-Add-Entity-Body-Yaw-API.patch | 65 + ...0786-Fix-force-opening-enchantment-tables.patch | 30 - patches/server/0787-Add-Entity-Body-Yaw-API.patch | 65 - ...64-Prevent-sleeping-villagers-moving-towa.patch | 24 + .../server/0788-Add-EntityFertilizeEggEvent.patch | 103 + ...64-Prevent-sleeping-villagers-moving-towa.patch | 24 - .../server/0789-Add-EntityFertilizeEggEvent.patch | 103 - ...anEntity-drop-not-updating-the-client-inv.patch | 30 + ...mpostItemEvent-and-EntityCompostItemEvent.patch | 45 + ...anEntity-drop-not-updating-the-client-inv.patch | 30 - ...mpostItemEvent-and-EntityCompostItemEvent.patch | 45 - ...-Correctly-handle-ArmorStand-invisibility.patch | 25 + ...-Correctly-handle-ArmorStand-invisibility.patch | 25 - ...ix-advancement-triggers-for-entity-damage.patch | 46 + ...ix-advancement-triggers-for-entity-damage.patch | 46 - .../0793-Fix-text-display-error-on-spawn.patch | 19 + ...-Fix-inventories-returning-null-Locations.patch | 61 + .../0794-Fix-text-display-error-on-spawn.patch | 19 - patches/server/0795-Add-Shearable-API.patch | 135 + ...-Fix-inventories-returning-null-Locations.patch | 61 - patches/server/0796-Add-Shearable-API.patch | 135 - .../0796-Fix-SpawnEggMeta-get-setSpawnedType.patch | 41 + .../0797-Fix-SpawnEggMeta-get-setSpawnedType.patch | 41 - ...elating-to-bad-recipes-in-furnace-like-ti.patch | 19 + ...elating-to-bad-recipes-in-furnace-like-ti.patch | 19 - ...t-sequence-violations-like-they-should-be.patch | 18 + ...sing-expired-keys-from-impacting-new-join.patch | 61 + ...t-sequence-violations-like-they-should-be.patch | 18 - ...meEvents-being-fired-from-unloaded-chunks.patch | 22 + ...sing-expired-keys-from-impacting-new-join.patch | 61 - ...meEvents-being-fired-from-unloaded-chunks.patch | 22 - .../0801-Use-array-for-gamerule-storage.patch | 52 + .../0802-Fix-a-couple-of-upstream-bed-issues.patch | 33 + .../0802-Use-array-for-gamerule-storage.patch | 52 - .../0803-Fix-a-couple-of-upstream-bed-issues.patch | 33 - ...0803-Fix-demo-flag-not-enabling-demo-mode.patch | 22 + .../0804-Add-Mob-Experience-reward-API.patch | 22 + ...0804-Fix-demo-flag-not-enabling-demo-mode.patch | 22 - .../0805-Add-Mob-Experience-reward-API.patch | 22 - ...Break-redstone-on-top-of-trap-doors-early.patch | 40 + ...Avoid-Lazy-Initialization-for-Enum-Fields.patch | 40 + ...Break-redstone-on-top-of-trap-doors-early.patch | 40 - ...Avoid-Lazy-Initialization-for-Enum-Fields.patch | 40 - .../0807-More-accurate-isInOpenWater-impl.patch | 27 + .../server/0808-Expand-PlayerItemMendEvent.patch | 67 + .../0808-More-accurate-isInOpenWater-impl.patch | 27 - .../server/0809-Expand-PlayerItemMendEvent.patch | 67 - ...-Refresh-ProjectileSource-for-projectiles.patch | 81 + .../server/0810-Add-transient-modifier-API.patch | 41 + ...-Refresh-ProjectileSource-for-projectiles.patch | 81 - .../server/0811-Add-transient-modifier-API.patch | 41 - patches/server/0811-Fix-block-place-logic.patch | 49 + patches/server/0812-Fix-block-place-logic.patch | 49 - ...ot-sound-playing-for-BlockItem-ItemStacks.patch | 23 + ...13-Call-BlockGrowEvent-for-missing-blocks.patch | 39 + ...ot-sound-playing-for-BlockItem-ItemStacks.patch | 23 - ...14-Call-BlockGrowEvent-for-missing-blocks.patch | 39 - ...ce-icanhasbukkit-default-if-alias-block-e.patch | 23 + ...ce-icanhasbukkit-default-if-alias-block-e.patch | 23 - ...fix-MapLike-spam-for-missing-key-selector.patch | 19 + .../0816-Fix-sniffer-removeExploredLocation.patch | 29 + ...fix-MapLike-spam-for-missing-key-selector.patch | 19 - ...ethod-to-remove-all-active-potion-effects.patch | 24 + .../0817-Fix-sniffer-removeExploredLocation.patch | 29 - .../0818-Add-event-for-player-editing-sign.patch | 93 + ...ethod-to-remove-all-active-potion-effects.patch | 24 - .../0819-Add-event-for-player-editing-sign.patch | 93 - ...ly-tick-item-frames-if-players-can-see-it.patch | 20 + ...-cmd-permission-levels-for-command-blocks.patch | 90 + ...ly-tick-item-frames-if-players-can-see-it.patch | 20 - .../0821-Add-option-to-disable-block-updates.patch | 179 + ...-cmd-permission-levels-for-command-blocks.patch | 90 - .../0822-Add-option-to-disable-block-updates.patch | 179 - .../0822-Call-missing-BlockDispenseEvent.patch | 88 + .../0823-Call-missing-BlockDispenseEvent.patch | 88 - ...t-load-chunks-for-supporting-block-checks.patch | 19 + ...t-load-chunks-for-supporting-block-checks.patch | 19 - .../0824-Optimize-player-lookups-for-beacons.patch | 36 + patches/server/0825-More-Sign-Block-API.patch | 62 + .../0825-Optimize-player-lookups-for-beacons.patch | 36 - patches/server/0826-More-Sign-Block-API.patch | 62 - .../0826-fix-item-meta-for-tadpole-buckets.patch | 63 + patches/server/0827-Fix-BanList-API.patch | 351 + .../0827-fix-item-meta-for-tadpole-buckets.patch | 63 - ...ava-and-water-fluid-explosion-resistance-.patch | 36 + patches/server/0828-Fix-BanList-API.patch | 351 - ...ava-and-water-fluid-explosion-resistance-.patch | 36 - ...829-Fix-possible-NPE-on-painting-creation.patch | 34 + ...830-Fix-possible-NPE-on-painting-creation.patch | 34 - ...spawnTimer-for-Wandering-Traders-spawned-.patch | 33 + ...xperienceOrb-should-call-EntitySpawnEvent.patch | 20 + ...spawnTimer-for-Wandering-Traders-spawned-.patch | 33 - ...xperienceOrb-should-call-EntitySpawnEvent.patch | 20 - ...methyst-throw-both-Spread-and-Grow-Events.patch | 24 + patches/server/0833-Add-whitelist-events.patch | 34 + ...methyst-throw-both-Spread-and-Grow-Events.patch | 24 - patches/server/0834-Add-whitelist-events.patch | 34 - .../0834-Implement-PlayerFailMoveEvent.patch | 111 + ...0835-Folia-scheduler-and-owned-region-API.patch | 1364 + .../0835-Implement-PlayerFailMoveEvent.patch | 111 - ...0836-Folia-scheduler-and-owned-region-API.patch | 1364 - ...ly-erase-allay-memory-on-non-item-targets.patch | 29 + ...x-rotation-when-spawning-display-entities.patch | 32 + ...ly-erase-allay-memory-on-non-item-targets.patch | 29 - ...x-rotation-when-spawning-display-entities.patch | 32 - .../0838-Only-capture-actual-tree-growth.patch | 75 + .../0839-Only-capture-actual-tree-growth.patch | 75 - ...ct-source-for-mushroom-block-spread-event.patch | 27 + ...domizeData-on-more-entities-when-spawning.patch | 68 + ...ct-source-for-mushroom-block-spread-event.patch | 27 - ...domizeData-on-more-entities-when-spawning.patch | 68 - .../0841-Use-correct-seed-on-api-world-load.patch | 19 + ...radeData-neighbour-ticks-outside-of-range.patch | 50 + .../0842-Use-correct-seed-on-api-world-load.patch | 19 - .../server/0843-Cache-map-ids-on-item-frames.patch | 39 + ...radeData-neighbour-ticks-outside-of-range.patch | 50 - .../0844-API-for-updating-recipes-on-clients.patch | 112 + .../server/0844-Cache-map-ids-on-item-frames.patch | 39 - .../0845-API-for-updating-recipes-on-clients.patch | 112 - ...45-Fix-custom-statistic-criteria-creation.patch | 23 + patches/server/0846-Bandaid-fix-for-Effect.patch | 179 + ...46-Fix-custom-statistic-criteria-creation.patch | 25 - patches/server/0847-Bandaid-fix-for-Effect.patch | 179 - patches/server/0847-SculkCatalyst-bloom-API.patch | 33 + .../0848-API-for-an-entity-s-scoreboard-name.patch | 24 + patches/server/0848-SculkCatalyst-bloom-API.patch | 33 - .../0849-API-for-an-entity-s-scoreboard-name.patch | 24 - ...nd-replace-methods-with-old-StructureType.patch | 54 + ...nd-replace-methods-with-old-StructureType.patch | 54 - ...omplete-namespaced-commands-if-send-names.patch | 28 + ...omplete-namespaced-commands-if-send-names.patch | 28 - ...operly-handle-BlockBreakEvent-isDropItems.patch | 162 + ...-Fire-entity-death-event-for-ender-dragon.patch | 25 + ...operly-handle-BlockBreakEvent-isDropItems.patch | 162 - ...ble-entity-tracking-range-by-Y-coordinate.patch | 30 + ...-Fire-entity-death-event-for-ender-dragon.patch | 25 - .../server/0854-Add-Listing-API-for-Player.patch | 186 + ...ble-entity-tracking-range-by-Y-coordinate.patch | 30 - .../server/0855-Add-Listing-API-for-Player.patch | 186 - ...55-Configurable-Region-Compression-Format.patch | 39 + .../0856-Add-BlockFace-to-BlockDamageEvent.patch | 39 + ...56-Configurable-Region-Compression-Format.patch | 39 - .../0857-Add-BlockFace-to-BlockDamageEvent.patch | 39 - .../server/0857-Fix-NPE-on-Boat-getStatus.patch | 32 + patches/server/0858-Expand-Pose-API.patch | 51 + .../server/0858-Fix-NPE-on-Boat-getStatus.patch | 32 - patches/server/0859-Expand-Pose-API.patch | 51 - patches/server/0859-More-DragonBattle-API.patch | 91 + patches/server/0860-Add-PlayerPickItemEvent.patch | 48 + patches/server/0860-More-DragonBattle-API.patch | 91 - patches/server/0861-Add-PlayerPickItemEvent.patch | 48 - .../server/0861-Allow-trident-custom-damage.patch | 39 + .../server/0862-Allow-trident-custom-damage.patch | 39 - .../0862-Expose-hand-in-BlockCanBuildEvent.patch | 32 + .../0863-Expose-hand-in-BlockCanBuildEvent.patch | 32 - ...timize-nearest-structure-border-iteration.patch | 39 + .../0864-Implement-OfflinePlayer-isConnected.patch | 42 + ...timize-nearest-structure-border-iteration.patch | 39 - patches/server/0865-Fix-slot-desync.patch | 129 + .../0865-Implement-OfflinePlayer-isConnected.patch | 42 - ...6-Add-titleOverride-to-InventoryOpenEvent.patch | 120 + patches/server/0866-Fix-slot-desync.patch | 129 - ...7-Add-titleOverride-to-InventoryOpenEvent.patch | 120 - .../0867-Configure-sniffer-egg-hatch-time.patch | 28 + .../0868-Configure-sniffer-egg-hatch-time.patch | 28 - ...portal-proximity-check-before-entity-look.patch | 75 + ...portal-proximity-check-before-entity-look.patch | 75 - ...0869-Skip-POI-finding-if-stuck-in-vehicle.patch | 32 + ...dd-slot-sanity-checks-in-container-clicks.patch | 43 + ...0870-Skip-POI-finding-if-stuck-in-vehicle.patch | 32 - ...dd-slot-sanity-checks-in-container-clicks.patch | 43 - ...871-Call-BlockRedstoneEvents-for-lecterns.patch | 27 + ...llow-proper-checking-of-empty-item-stacks.patch | 31 + ...872-Call-BlockRedstoneEvents-for-lecterns.patch | 27 - ...llow-proper-checking-of-empty-item-stacks.patch | 31 - ...0873-Fix-silent-equipment-change-for-mobs.patch | 113 + ...0874-Fix-silent-equipment-change-for-mobs.patch | 113 - .../server/0874-Fix-spigot-s-Forced-Stats.patch | 54 + ...d-missing-InventoryHolders-to-inventories.patch | 314 + .../server/0875-Fix-spigot-s-Forced-Stats.patch | 54 - ...d-missing-InventoryHolders-to-inventories.patch | 314 - ...-tile-entities-in-chunks-that-are-positio.patch | 43 + ...dd-missing-logs-for-log-ips-config-option.patch | 37 + ...-tile-entities-in-chunks-that-are-positio.patch | 43 - ...dd-missing-logs-for-log-ips-config-option.patch | 37 - ...ndition-on-UpgradeData.BlockFixers-class-.patch | 27 + ...NPE-in-AdvancementProgress-getDateAwarded.patch | 19 + ...ndition-on-UpgradeData.BlockFixers-class-.patch | 27 - ...NPE-in-AdvancementProgress-getDateAwarded.patch | 19 - ...team-sidebar-objectives-not-being-cleared.patch | 25 + ...881-Fix-missing-map-initialize-event-call.patch | 48 + ...team-sidebar-objectives-not-being-cleared.patch | 25 - ...882-Fix-missing-map-initialize-event-call.patch | 48 - ...ty-data-when-attaching-firework-to-entity.patch | 23 + .../0883-Fix-UnsafeValues-loadAdvancement.patch | 43 + ...ty-data-when-attaching-firework-to-entity.patch | 23 - .../server/0884-Add-player-idle-duration-API.patch | 30 + .../0884-Fix-UnsafeValues-loadAdvancement.patch | 43 - .../server/0885-Add-player-idle-duration-API.patch | 30 - ...-check-if-we-can-see-non-visible-entities.patch | 19 + ...-check-if-we-can-see-non-visible-entities.patch | 19 - ...6-Fix-NPE-in-SculkBloomEvent-world-access.patch | 43 + ...-itemstack-for-Player-sendEquipmentChange.patch | 19 + ...7-Fix-NPE-in-SculkBloomEvent-world-access.patch | 43 - ...-itemstack-for-Player-sendEquipmentChange.patch | 19 - patches/server/0888-Optimize-VarInts.patch | 52 + ...get-the-collision-shape-of-a-block-before.patch | 32 + patches/server/0889-Optimize-VarInts.patch | 52 - ...get-the-collision-shape-of-a-block-before.patch | 32 - ...-Add-predicate-for-blocks-when-raytracing.patch | 116 + ...-Add-predicate-for-blocks-when-raytracing.patch | 116 - ...ake-item-packets-with-collector-as-source.patch | 20 + ...ake-item-packets-with-collector-as-source.patch | 20 - .../server/0892-Expand-LingeringPotion-API.patch | 19 + .../server/0893-Expand-LingeringPotion-API.patch | 19 - ...ightningEffect-powers-lightning-rods-and-.patch | 72 + ...to-fish-event-for-all-player-interactions.patch | 75 + ...ightningEffect-powers-lightning-rods-and-.patch | 72 - ...to-fish-event-for-all-player-interactions.patch | 75 - ...-Fix-several-issues-with-EntityBreedEvent.patch | 118 + .../0896-Add-UUID-attribute-modifier-API.patch | 142 + ...-Fix-several-issues-with-EntityBreedEvent.patch | 118 - .../0897-Add-UUID-attribute-modifier-API.patch | 142 - ...issing-event-call-for-entity-teleport-API.patch | 28 + ...issing-event-call-for-entity-teleport-API.patch | 28 - ...-Lazily-create-LootContext-for-criterions.patch | 30 + ...99-Don-t-fire-sync-events-during-worldgen.patch | 208 + ...-Lazily-create-LootContext-for-criterions.patch | 30 - patches/server/0900-Add-Structure-check-API.patch | 26 + ...00-Don-t-fire-sync-events-during-worldgen.patch | 208 - patches/server/0901-Add-Structure-check-API.patch | 26 - ...taItem-getAttributeModifier-duplication-c.patch | 19 + ...taItem-getAttributeModifier-duplication-c.patch | 19 - ...902-Restore-vanilla-entity-drops-behavior.patch | 269 + .../0903-Dont-resend-blocks-on-interactions.patch | 171 + ...903-Restore-vanilla-entity-drops-behavior.patch | 269 - .../0904-Dont-resend-blocks-on-interactions.patch | 171 - patches/server/0904-add-more-scoreboard-API.patch | 79 + patches/server/0905-Improve-Registry.patch | 102 + patches/server/0905-add-more-scoreboard-API.patch | 79 - ...x-NPE-on-null-loc-for-EntityTeleportEvent.patch | 66 + patches/server/0906-Improve-Registry.patch | 102 - .../server/0907-Add-experience-points-API.patch | 73 + ...x-NPE-on-null-loc-for-EntityTeleportEvent.patch | 66 - .../server/0908-Add-drops-to-shear-events.patch | 400 + .../server/0908-Add-experience-points-API.patch | 73 - .../server/0909-Add-PlayerShieldDisableEvent.patch | 53 + .../server/0909-Add-drops-to-shear-events.patch | 400 - .../server/0910-Add-PlayerShieldDisableEvent.patch | 53 - ...-Validate-ResourceLocation-in-NBT-reading.patch | 173 + ...handle-experience-dropping-on-block-break.patch | 94 + ...-Validate-ResourceLocation-in-NBT-reading.patch | 173 - .../server/0912-Fixup-NamespacedKey-handling.patch | 170 + ...handle-experience-dropping-on-block-break.patch | 94 - .../0913-Expose-LootTable-of-DecoratedPot.patch | 44 + .../server/0913-Fixup-NamespacedKey-handling.patch | 170 - .../0914-Expose-LootTable-of-DecoratedPot.patch | 44 - ...uce-allocation-of-Vec3D-by-entity-tracker.patch | 59 + ...-PlayerTradeEvent-and-PlayerPurchaseEvent.patch | 240 + ...uce-allocation-of-Vec3D-by-entity-tracker.patch | 59 - ...-PlayerTradeEvent-and-PlayerPurchaseEvent.patch | 240 - .../server/0916-Add-ShulkerDuplicateEvent.patch | 22 + .../server/0917-Add-ShulkerDuplicateEvent.patch | 22 - ...0917-Add-api-for-spawn-egg-texture-colors.patch | 26 + .../server/0918-Add-Lifecycle-Event-system.patch | 785 + ...0918-Add-api-for-spawn-egg-texture-colors.patch | 26 - .../server/0919-Add-Lifecycle-Event-system.patch | 785 - patches/server/0919-ItemStack-Tooltip-API.patch | 30 + ...tChunkSnapshot-includeLightData-parameter.patch | 70 + patches/server/0920-ItemStack-Tooltip-API.patch | 32 - patches/server/0921-Add-FluidState-API.patch | 208 + ...tChunkSnapshot-includeLightData-parameter.patch | 70 - patches/server/0922-Add-FluidState-API.patch | 208 - patches/server/0922-add-number-format-api.patch | 138 + patches/server/0923-add-number-format-api.patch | 138 - patches/server/0923-improve-BanList-types.patch | 32 + patches/server/0924-Expanded-Hopper-API.patch | 31 + patches/server/0924-improve-BanList-types.patch | 32 - .../0925-Add-BlockBreakProgressUpdateEvent.patch | 28 + patches/server/0925-Expanded-Hopper-API.patch | 31 - .../0926-Add-BlockBreakProgressUpdateEvent.patch | 28 - .../server/0926-Deprecate-ItemStack-setType.patch | 35 + patches/server/0927-Add-CartographyItemEvent.patch | 43 + .../server/0927-Deprecate-ItemStack-setType.patch | 35 - patches/server/0928-Add-CartographyItemEvent.patch | 43 - patches/server/0928-More-Raid-API.patch | 106 + ...boarding-message-for-initial-server-start.patch | 103 + patches/server/0929-More-Raid-API.patch | 106 - ...boarding-message-for-initial-server-start.patch | 103 - .../0930-Configurable-max-block-fluid-ticks.patch | 22 + .../0931-Configurable-max-block-fluid-ticks.patch | 22 - .../server/0931-Fix-bees-aging-inside-hives.patch | 41 + .../0932-Disable-memory-reserve-allocating.patch | 19 + .../server/0932-Fix-bees-aging-inside-hives.patch | 41 - .../0933-Disable-memory-reserve-allocating.patch | 19 - ...DamageByEntityEvent-for-unowned-wither-sk.patch | 19 + ...DamageByEntityEvent-for-unowned-wither-sk.patch | 19 - patches/server/0934-Fix-DamageSource-API.patch | 234 + patches/server/0935-Fix-DamageSource-API.patch | 234 - ...n-of-invalid-block-entity-during-world-ge.patch | 59 + ...n-of-invalid-block-entity-during-world-ge.patch | 59 - ...ble-StackOverflowError-for-some-dispenses.patch | 95 + ...ble-StackOverflowError-for-some-dispenses.patch | 95 - .../server/0937-Improve-tag-parser-handling.patch | 285 + .../server/0938-Improve-tag-parser-handling.patch | 285 - patches/server/0938-Item-Mutation-Fixes.patch | 38 + patches/server/0939-Item-Mutation-Fixes.patch | 38 - .../0939-Per-world-ticks-per-spawn-settings.patch | 35 + .../0940-Per-world-ticks-per-spawn-settings.patch | 35 - ...ack-the-changed-item-from-dispense-events.patch | 104 + ...ack-the-changed-item-from-dispense-events.patch | 104 - ...rock-and-End-Portal-Frames-from-being-des.patch | 171 + ...config-for-mobs-immune-to-default-effects.patch | 44 + ...rock-and-End-Portal-Frames-from-being-des.patch | 169 - ...config-for-mobs-immune-to-default-effects.patch | 44 - .../server/0943-Deep-clone-nbt-tags-in-PDC.patch | 45 + .../server/0944-Deep-clone-nbt-tags-in-PDC.patch | 45 - .../0944-Support-old-UUID-format-for-NBT.patch | 63 + .../0945-Fix-shield-disable-inconsistency.patch | 22 + .../0945-Support-old-UUID-format-for-NBT.patch | 63 - .../0946-Fix-shield-disable-inconsistency.patch | 22 - ...Handle-Large-Packets-disconnecting-client.patch | 135 + patches/server/0947-Fix-ItemFlags.patch | 199 + ...Handle-Large-Packets-disconnecting-client.patch | 135 - patches/server/0948-Fix-ItemFlags.patch | 199 - ...x-helmet-damage-reduction-inconsistencies.patch | 21 + ...x-helmet-damage-reduction-inconsistencies.patch | 21 - ...anilla-handling-of-LivingEntity-actuallyH.patch | 50 + ...anilla-handling-of-LivingEntity-actuallyH.patch | 50 - ...improve-checking-handled-tags-in-itemmeta.patch | 887 + .../0951-Expose-hasColor-to-leather-armor.patch | 38 + ...improve-checking-handled-tags-in-itemmeta.patch | 887 - ...-Added-API-to-get-player-ha-proxy-address.patch | 65 + .../0952-Expose-hasColor-to-leather-armor.patch | 38 - ...-Added-API-to-get-player-ha-proxy-address.patch | 65 - patches/server/0953-General-ItemMeta-fixes.patch | 2152 ++ patches/server/0954-General-ItemMeta-fixes.patch | 2152 -- patches/server/0954-More-Chest-Block-API.patch | 73 + patches/server/0955-More-Chest-Block-API.patch | 73 - ...int-data-component-type-on-encoding-error.patch | 24 + .../server/0956-Brigadier-based-command-API.patch | 2829 ++ ...int-data-component-type-on-encoding-error.patch | 24 - .../server/0957-Brigadier-based-command-API.patch | 2831 -- .../server/0957-Fix-issues-with-Recipe-API.patch | 102 + .../0958-Fix-equipment-slot-and-group-API.patch | 136 + .../server/0958-Fix-issues-with-Recipe-API.patch | 102 - ...kkit-plugin-to-use-Paper-PluginLoader-API.patch | 130 + .../0959-Fix-equipment-slot-and-group-API.patch | 136 - ...kkit-plugin-to-use-Paper-PluginLoader-API.patch | 130 - ...ding-oversized-item-data-in-equipment-and.patch | 236 + ...-Prevent-NPE-if-hooked-entity-was-cleared.patch | 24 + ...ding-oversized-item-data-in-equipment-and.patch | 236 - ...ncelling-BlockPlaceEvent-calling-onRemove.patch | 47 + ...-Prevent-NPE-if-hooked-entity-was-cleared.patch | 24 - .../0963-Add-missing-fishing-event-state.patch | 26 + ...ncelling-BlockPlaceEvent-calling-onRemove.patch | 47 - .../0964-Add-missing-fishing-event-state.patch | 26 - ...Deprecate-InvAction-HOTBAR_MOVE_AND_READD.patch | 26 + ...Deprecate-InvAction-HOTBAR_MOVE_AND_READD.patch | 26 - ...-disconnect-packet-in-phases-where-it-doe.patch | 21 + patches/server/0966-Adopt-MaterialRerouting.patch | 134 + ...-disconnect-packet-in-phases-where-it-doe.patch | 21 - patches/server/0967-Adopt-MaterialRerouting.patch | 134 - .../server/0967-Suspicious-Effect-Entry-API.patch | 231 + .../server/0968-Suspicious-Effect-Entry-API.patch | 231 - ...968-check-if-itemstack-is-stackable-first.patch | 19 + ...-Fix-removing-recipes-from-RecipeIterator.patch | 39 + ...969-check-if-itemstack-is-stackable-first.patch | 19 - ...ble-damage-tick-when-blocking-with-shield.patch | 19 + ...-Fix-removing-recipes-from-RecipeIterator.patch | 39 - ...ble-damage-tick-when-blocking-with-shield.patch | 19 - ...move-the-experimental-smithing-inventory-.patch | 26 + ...move-the-experimental-smithing-inventory-.patch | 26 - .../0972-disable-forced-empty-world-ticks.patch | 19 + ...InWorldBounds-and-getBlockState-for-inlin.patch | 99 + .../0973-disable-forced-empty-world-ticks.patch | 19 - ...s-in-item-frames-performance-and-bug-fixe.patch | 137 + ...InWorldBounds-and-getBlockState-for-inlin.patch | 99 - ...s-in-item-frames-performance-and-bug-fixe.patch | 137 - ...twork-Manager-and-add-advanced-packet-sup.patch | 395 + .../0976-Allow-Saving-of-Oversized-Chunks.patch | 204 + ...twork-Manager-and-add-advanced-packet-sup.patch | 395 - .../0977-Allow-Saving-of-Oversized-Chunks.patch | 204 - .../0977-Flat-bedrock-generator-settings.patch | 292 + .../server/0978-Entity-Activation-Range-2.0.patch | 781 + .../0978-Flat-bedrock-generator-settings.patch | 292 - patches/server/0979-Anti-Xray.patch | 1663 + .../server/0979-Entity-Activation-Range-2.0.patch | 807 - patches/server/0980-Anti-Xray.patch | 1663 - ...e-Velocity-compression-and-cipher-natives.patch | 375 + ...981-Optimize-Collision-to-not-load-chunks.patch | 108 + ...e-Velocity-compression-and-cipher-natives.patch | 375 - ...982-Optimize-Collision-to-not-load-chunks.patch | 108 - ...ize-GoalSelector-Goal.Flag-Set-operations.patch | 160 + ...ize-GoalSelector-Goal.Flag-Set-operations.patch | 160 - patches/server/0983-Optimize-Hoppers.patch | 664 + patches/server/0984-Optimize-Hoppers.patch | 664 - .../server/0984-Optimize-Voxel-Shape-Merging.patch | 123 + .../0985-Optimize-Bit-Operations-by-inlining.patch | 213 + .../server/0985-Optimize-Voxel-Shape-Merging.patch | 123 - .../0986-Optimize-Bit-Operations-by-inlining.patch | 213 - .../server/0986-Remove-streams-from-hot-code.patch | 215 + ...thfinder-Remove-Streams-Optimized-collect.patch | 134 + .../server/0987-Remove-streams-from-hot-code.patch | 215 - ...entity-type-tags-suggestions-in-selectors.patch | 152 + ...thfinder-Remove-Streams-Optimized-collect.patch | 134 - ...entity-type-tags-suggestions-in-selectors.patch | 152 - ...Handle-Oversized-block-entities-in-chunks.patch | 64 + ...990-Check-distance-in-entity-interactions.patch | 68 + ...Handle-Oversized-block-entities-in-chunks.patch | 64 - ...991-Check-distance-in-entity-interactions.patch | 68 - patches/server/0991-Configurable-Sand-Duping.patch | 19 + patches/server/0992-Configurable-Sand-Duping.patch | 19 - patches/server/0992-Properly-resend-entities.patch | 272 + patches/server/0993-Properly-resend-entities.patch | 272 - .../server/0993-Registry-Modification-API.patch | 1499 + .../0994-Add-registry-entry-and-builders.patch | 484 + .../server/0994-Registry-Modification-API.patch | 1499 - .../0995-Add-registry-entry-and-builders.patch | 484 - .../0995-Proxy-ItemStack-to-CraftItemStack.patch | 302 + ...C-view-accessible-directly-from-ItemStack.patch | 271 + .../0996-Proxy-ItemStack-to-CraftItemStack.patch | 302 - ...C-view-accessible-directly-from-ItemStack.patch | 271 - ...Minecraft-commands-in-function-parsing-an.patch | 135 + ...Minecraft-commands-in-function-parsing-an.patch | 135 - .../0998-optimize-dirt-and-snow-spreading.patch | 78 + .../0999-Fix-NPE-for-Jukebox-setRecord.patch | 20 + .../0999-optimize-dirt-and-snow-spreading.patch | 78 - .../1000-Fix-NPE-for-Jukebox-setRecord.patch | 20 - patches/server/1000-fix-horse-inventories.patch | 215 + ...ll-EntityDamageEvents-before-actuallyHurt.patch | 73 + patches/server/1001-fix-horse-inventories.patch | 215 - .../server/1002-Add-ItemType-getItemRarity.patch | 23 + ...ll-EntityDamageEvents-before-actuallyHurt.patch | 73 - .../server/1003-Add-ItemType-getItemRarity.patch | 23 - .../server/1003-Add-plugin-info-at-startup.patch | 64 + .../server/1004-Add-plugin-info-at-startup.patch | 64 - ...nteraction-leniency-distance-configurable.patch | 26 + .../1005-Fix-PickupStatus-getting-reset.patch | 65 + ...nteraction-leniency-distance-configurable.patch | 26 - ...lock-type-in-SculkSensorBlock-canActivate.patch | 19 + .../1006-Fix-PickupStatus-getting-reset.patch | 65 - ...-for-CanPlaceOn-and-CanDestroy-NBT-values.patch | 157 + ...lock-type-in-SculkSensorBlock-canActivate.patch | 19 - ...-for-CanPlaceOn-and-CanDestroy-NBT-values.patch | 157 - ...guration-for-horizontal-only-item-merging.patch | 28 + .../1009-Add-skipping-world-symlink-scan.patch | 21 + ...guration-for-horizontal-only-item-merging.patch | 28 - .../1010-Add-even-more-Enchantment-API.patch | 47 + .../1010-Add-skipping-world-symlink-scan.patch | 21 - .../1011-Add-even-more-Enchantment-API.patch | 47 - patches/server/1011-Leashable-API.patch | 161 + .../server/1012-Fix-CraftBukkit-drag-system.patch | 54 + patches/server/1012-Leashable-API.patch | 161 - .../server/1013-Fix-CraftBukkit-drag-system.patch | 54 - ...loomEvent-firing-for-block-entity-loading.patch | 39 + ...loomEvent-firing-for-block-entity-loading.patch | 39 - ...damage-lootable-item-function-from-compas.patch | 41 + .../1015-Add-enchantment-seed-update-API.patch | 39 + ...damage-lootable-item-function-from-compas.patch | 41 - .../1016-Add-enchantment-seed-update-API.patch | 39 - ...nise-sending-chat-to-client-with-updating.patch | 27 + .../1017-Fix-InventoryOpenEvent-cancellation.patch | 352 + ...nise-sending-chat-to-client-with-updating.patch | 27 - ...1018-Fire-BlockExpEvent-on-grindstone-use.patch | 23 + .../1018-Fix-InventoryOpenEvent-cancellation.patch | 352 - .../server/1019-Check-dead-flag-in-isAlive.patch | 29 + ...1019-Fire-BlockExpEvent-on-grindstone-use.patch | 23 - patches/server/1020-Add-FeatureFlag-API.patch | 430 + .../server/1020-Check-dead-flag-in-isAlive.patch | 29 - patches/server/1021-Add-FeatureFlag-API.patch | 430 - patches/server/1021-Tag-Lifecycle-Events.patch | 595 + .../server/1022-Item-serialization-as-json.patch | 73 + patches/server/1022-Tag-Lifecycle-Events.patch | 595 - .../server/1023-Item-serialization-as-json.patch | 73 - ...-Validate-slot-in-PlayerInventory-setSlot.patch | 26 + ...ove-wall-time-unused-skip-tick-protection.patch | 163 + ...-Validate-slot-in-PlayerInventory-setSlot.patch | 26 - ...le-pretty-printing-for-advancement-saving.patch | 22 + ...ove-wall-time-unused-skip-tick-protection.patch | 163 - ...le-pretty-printing-for-advancement-saving.patch | 22 - ...CommandPreprocessEvent-on-signed-commands.patch | 52 + ...tWithLevels-with-enchantment-registry-set.patch | 33 + ...CommandPreprocessEvent-on-signed-commands.patch | 52 - ...tWithLevels-with-enchantment-registry-set.patch | 33 - .../server/1028-Improve-entity-effect-API.patch | 154 + patches/server/1029-Add-recipeBrewTime.patch | 181 + .../server/1029-Improve-entity-effect-API.patch | 154 - patches/server/1030-Add-recipeBrewTime.patch | 181 - .../1030-Call-bucket-events-for-cauldrons.patch | 203 + .../1031-Add-PlayerInsertLecternBookEvent.patch | 36 + .../1031-Call-bucket-events-for-cauldrons.patch | 203 - .../1032-Add-PlayerInsertLecternBookEvent.patch | 36 - .../1032-Void-damage-configuration-API.patch | 93 + patches/server/1033-Add-Offline-PDC-API.patch | 45 + .../1033-Void-damage-configuration-API.patch | 93 - ...vilView-bypassEnchantmentLevelRestriction.patch | 53 + patches/server/1034-Add-Offline-PDC-API.patch | 45 - ...vilView-bypassEnchantmentLevelRestriction.patch | 53 - ...35-Add-proper-async-player-disconnections.patch | 168 + ...36-Add-proper-async-player-disconnections.patch | 168 - ...Always-send-Banner-patterns-to-the-client.patch | 42 + ...Always-send-Banner-patterns-to-the-client.patch | 42 - .../server/1037-Rewrite-dataconverter-system.patch | 30407 ++++++++++++++++ .../1038-Moonrise-optimisation-patches.patch | 36230 ++++++++++++++++++ .../server/1038-Rewrite-dataconverter-system.patch | 30407 ---------------- .../server/1039-API-for-checking-sent-chunks.patch | 46 + .../1039-Moonrise-optimisation-patches.patch | 36236 ------------------- .../server/1040-API-for-checking-sent-chunks.patch | 46 - .../1040-Fix-CraftWorld-isChunkGenerated.patch | 44 + ...d-startup-flag-to-disable-gamerule-limits.patch | 38 + .../1041-Fix-CraftWorld-isChunkGenerated.patch | 44 - ...d-startup-flag-to-disable-gamerule-limits.patch | 38 - .../server/1042-Improved-Watchdog-Support.patch | 473 + ...Detail-more-information-in-watchdog-dumps.patch | 295 + .../server/1043-Improved-Watchdog-Support.patch | 473 - ...Detail-more-information-in-watchdog-dumps.patch | 296 - .../1044-Entity-load-save-limit-per-chunk.patch | 81 + ...recalculate-regionfile-header-if-it-is-co.patch | 742 + .../1045-Entity-load-save-limit-per-chunk.patch | 81 - ...recalculate-regionfile-header-if-it-is-co.patch | 742 - patches/server/1046-Bundle-spark.patch | 371 + patches/server/1047-Bundle-spark.patch | 371 - .../1047-Improve-performance-of-mass-crafts.patch | 92 + .../1048-Improve-performance-of-mass-crafts.patch | 92 - .../1048-Incremental-chunk-and-player-saving.patch | 133 + .../1049-Incremental-chunk-and-player-saving.patch | 139 - .../server/1049-Optimise-general-POI-access.patch | 1061 + ...tracker-desync-when-new-players-are-added.patch | 105 + .../server/1050-Optimise-general-POI-access.patch | 1061 - ...tracker-desync-when-new-players-are-added.patch | 105 - patches/server/1051-Lag-compensation-ticks.patch | 129 + patches/server/1052-Lag-compensation-ticks.patch | 129 - ...llision-checking-in-player-move-packet-ha.patch | 168 + ...llision-checking-in-player-move-packet-ha.patch | 168 - .../1053-Optional-per-player-mob-spawns.patch | 232 + ...celling-PreCreatureSpawnEvent-with-per-pl.patch | 89 + .../1054-Optional-per-player-mob-spawns.patch | 232 - ...celling-PreCreatureSpawnEvent-with-per-pl.patch | 89 - 1120 files changed, 118516 insertions(+), 119846 deletions(-) create mode 100644 patches/server/0023-Further-improve-server-tick-loop.patch delete mode 100644 patches/server/0023-Timings-v2.patch delete mode 100644 patches/server/0024-Further-improve-server-tick-loop.patch create mode 100644 patches/server/0024-Remove-Spigot-timings.patch create mode 100644 patches/server/0601-Oprimise-map-impl-for-tracked-players.patch delete mode 100644 patches/server/0601-Time-scoreboard-search.patch create mode 100644 patches/server/0602-Add-missing-InventoryType.patch delete mode 100644 patches/server/0602-Oprimise-map-impl-for-tracked-players.patch delete mode 100644 patches/server/0603-Add-missing-InventoryType.patch create mode 100644 patches/server/0603-Optimise-BlockSoil-nearby-water-lookup.patch create mode 100644 patches/server/0604-Fix-merchant-inventory-not-closing-on-entity-removal.patch delete mode 100644 patches/server/0604-Optimise-BlockSoil-nearby-water-lookup.patch create mode 100644 patches/server/0605-Check-requirement-before-suggesting-root-nodes.patch delete mode 100644 patches/server/0605-Fix-merchant-inventory-not-closing-on-entity-removal.patch delete mode 100644 patches/server/0606-Check-requirement-before-suggesting-root-nodes.patch create mode 100644 patches/server/0606-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch create mode 100644 patches/server/0607-Add-packet-limiter-config.patch delete mode 100644 patches/server/0607-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch delete mode 100644 patches/server/0608-Add-packet-limiter-config.patch create mode 100644 patches/server/0608-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch create mode 100644 patches/server/0609-Ensure-valid-vehicle-status.patch delete mode 100644 patches/server/0609-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch delete mode 100644 patches/server/0610-Ensure-valid-vehicle-status.patch create mode 100644 patches/server/0610-Prevent-softlocked-end-exit-portal-generation.patch create mode 100644 patches/server/0611-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch delete mode 100644 patches/server/0611-Prevent-softlocked-end-exit-portal-generation.patch create mode 100644 patches/server/0612-Don-t-log-debug-logging-being-disabled.patch delete mode 100644 patches/server/0612-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch delete mode 100644 patches/server/0613-Don-t-log-debug-logging-being-disabled.patch create mode 100644 patches/server/0613-fix-various-menus-with-empty-level-accesses.patch create mode 100644 patches/server/0614-Preserve-overstacked-loot.patch delete mode 100644 patches/server/0614-fix-various-menus-with-empty-level-accesses.patch delete mode 100644 patches/server/0615-Preserve-overstacked-loot.patch create mode 100644 patches/server/0615-Update-head-rotation-in-missing-places.patch delete mode 100644 patches/server/0616-Update-head-rotation-in-missing-places.patch create mode 100644 patches/server/0616-prevent-unintended-light-block-manipulation.patch create mode 100644 patches/server/0617-Fix-CraftCriteria-defaults-map.patch delete mode 100644 patches/server/0617-prevent-unintended-light-block-manipulation.patch delete mode 100644 patches/server/0618-Fix-CraftCriteria-defaults-map.patch create mode 100644 patches/server/0618-Fix-upstreams-block-state-factories.patch create mode 100644 patches/server/0619-Configurable-feature-seeds.patch delete mode 100644 patches/server/0619-Fix-upstreams-block-state-factories.patch create mode 100644 patches/server/0620-Add-root-admin-user-detection.patch delete mode 100644 patches/server/0620-Configurable-feature-seeds.patch delete mode 100644 patches/server/0621-Add-root-admin-user-detection.patch create mode 100644 patches/server/0621-don-t-attempt-to-teleport-dead-entities.patch create mode 100644 patches/server/0622-Prevent-excessive-velocity-through-repeated-crits.patch delete mode 100644 patches/server/0622-don-t-attempt-to-teleport-dead-entities.patch delete mode 100644 patches/server/0623-Prevent-excessive-velocity-through-repeated-crits.patch create mode 100644 patches/server/0623-Remove-client-side-code-using-deprecated-for-removal.patch create mode 100644 patches/server/0624-Fix-Spigot-growth-modifiers.patch delete mode 100644 patches/server/0624-Remove-client-side-code-using-deprecated-for-removal.patch delete mode 100644 patches/server/0625-Fix-Spigot-growth-modifiers.patch create mode 100644 patches/server/0625-Prevent-ContainerOpenersCounter-openCount-from-going.patch create mode 100644 patches/server/0626-Add-PlayerItemFrameChangeEvent.patch delete mode 100644 patches/server/0626-Prevent-ContainerOpenersCounter-openCount-from-going.patch delete mode 100644 patches/server/0627-Add-PlayerItemFrameChangeEvent.patch create mode 100644 patches/server/0627-Optimize-HashMapPalette.patch create mode 100644 patches/server/0628-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch delete mode 100644 patches/server/0628-Optimize-HashMapPalette.patch create mode 100644 patches/server/0629-Add-more-Campfire-API.patch delete mode 100644 patches/server/0629-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch delete mode 100644 patches/server/0630-Add-more-Campfire-API.patch create mode 100644 patches/server/0630-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch create mode 100644 patches/server/0631-Forward-CraftEntity-in-teleport-command.patch delete mode 100644 patches/server/0631-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch delete mode 100644 patches/server/0632-Forward-CraftEntity-in-teleport-command.patch create mode 100644 patches/server/0632-Improve-scoreboard-entries.patch create mode 100644 patches/server/0633-Entity-powdered-snow-API.patch delete mode 100644 patches/server/0633-Improve-scoreboard-entries.patch create mode 100644 patches/server/0634-Add-API-for-item-entity-health.patch delete mode 100644 patches/server/0634-Entity-powdered-snow-API.patch delete mode 100644 patches/server/0635-Add-API-for-item-entity-health.patch create mode 100644 patches/server/0635-Configurable-max-block-light-for-monster-spawning.patch delete mode 100644 patches/server/0636-Configurable-max-block-light-for-monster-spawning.patch create mode 100644 patches/server/0636-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch create mode 100644 patches/server/0637-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch delete mode 100644 patches/server/0637-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch create mode 100644 patches/server/0638-Bucketable-API.patch delete mode 100644 patches/server/0638-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch delete mode 100644 patches/server/0639-Bucketable-API.patch create mode 100644 patches/server/0639-Validate-usernames.patch create mode 100644 patches/server/0640-Make-water-animal-spawn-height-configurable.patch delete mode 100644 patches/server/0640-Validate-usernames.patch create mode 100644 patches/server/0641-Expose-vanilla-BiomeProvider-from-WorldInfo.patch delete mode 100644 patches/server/0641-Make-water-animal-spawn-height-configurable.patch create mode 100644 patches/server/0642-Add-config-option-for-worlds-affected-by-time-cmd.patch delete mode 100644 patches/server/0642-Expose-vanilla-BiomeProvider-from-WorldInfo.patch delete mode 100644 patches/server/0643-Add-config-option-for-worlds-affected-by-time-cmd.patch create mode 100644 patches/server/0643-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch delete mode 100644 patches/server/0644-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch create mode 100644 patches/server/0644-Multiple-Entries-with-Scoreboards.patch delete mode 100644 patches/server/0645-Multiple-Entries-with-Scoreboards.patch create mode 100644 patches/server/0645-Reset-placed-block-on-exception.patch create mode 100644 patches/server/0646-Add-configurable-height-for-slime-spawn.patch delete mode 100644 patches/server/0646-Reset-placed-block-on-exception.patch delete mode 100644 patches/server/0647-Add-configurable-height-for-slime-spawn.patch create mode 100644 patches/server/0647-Fix-xp-reward-for-baby-zombies.patch delete mode 100644 patches/server/0648-Fix-xp-reward-for-baby-zombies.patch create mode 100644 patches/server/0648-Multi-Block-Change-API-Implementation.patch create mode 100644 patches/server/0649-Fix-NotePlayEvent.patch delete mode 100644 patches/server/0649-Multi-Block-Change-API-Implementation.patch delete mode 100644 patches/server/0650-Fix-NotePlayEvent.patch create mode 100644 patches/server/0650-Freeze-Tick-Lock-API.patch delete mode 100644 patches/server/0651-Freeze-Tick-Lock-API.patch create mode 100644 patches/server/0651-More-PotionEffectType-API.patch delete mode 100644 patches/server/0652-More-PotionEffectType-API.patch create mode 100644 patches/server/0652-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch create mode 100644 patches/server/0653-API-for-creating-command-sender-which-forwards-feedb.patch delete mode 100644 patches/server/0653-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch delete mode 100644 patches/server/0654-API-for-creating-command-sender-which-forwards-feedb.patch create mode 100644 patches/server/0654-Add-missing-structure-set-seed-configs.patch delete mode 100644 patches/server/0655-Add-missing-structure-set-seed-configs.patch create mode 100644 patches/server/0655-Fix-cancelled-powdered-snow-bucket-placement.patch create mode 100644 patches/server/0656-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch delete mode 100644 patches/server/0656-Fix-cancelled-powdered-snow-bucket-placement.patch create mode 100644 patches/server/0657-Add-GameEvent-tags.patch delete mode 100644 patches/server/0657-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch delete mode 100644 patches/server/0658-Add-GameEvent-tags.patch create mode 100644 patches/server/0658-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch delete mode 100644 patches/server/0659-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch create mode 100644 patches/server/0659-Furnace-RecipesUsed-API.patch create mode 100644 patches/server/0660-Configurable-sculk-sensor-listener-range.patch delete mode 100644 patches/server/0660-Furnace-RecipesUsed-API.patch create mode 100644 patches/server/0661-Add-missing-block-data-API.patch delete mode 100644 patches/server/0661-Configurable-sculk-sensor-listener-range.patch delete mode 100644 patches/server/0662-Add-missing-block-data-API.patch create mode 100644 patches/server/0662-Option-to-have-default-CustomSpawners-in-custom-worl.patch delete mode 100644 patches/server/0663-Option-to-have-default-CustomSpawners-in-custom-worl.patch create mode 100644 patches/server/0663-Put-world-into-worldlist-before-initing-the-world.patch create mode 100644 patches/server/0664-Custom-Potion-Mixes.patch delete mode 100644 patches/server/0664-Put-world-into-worldlist-before-initing-the-world.patch delete mode 100644 patches/server/0665-Custom-Potion-Mixes.patch create mode 100644 patches/server/0665-Force-close-world-loading-screen.patch create mode 100644 patches/server/0666-Fix-falling-block-spawn-methods.patch delete mode 100644 patches/server/0666-Force-close-world-loading-screen.patch create mode 100644 patches/server/0667-Expose-furnace-minecart-push-values.patch delete mode 100644 patches/server/0667-Fix-falling-block-spawn-methods.patch delete mode 100644 patches/server/0668-Expose-furnace-minecart-push-values.patch create mode 100644 patches/server/0668-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch delete mode 100644 patches/server/0669-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch create mode 100644 patches/server/0669-More-Projectile-API.patch create mode 100644 patches/server/0670-Fix-swamp-hut-cat-generation-deadlock.patch delete mode 100644 patches/server/0670-More-Projectile-API.patch create mode 100644 patches/server/0671-Don-t-allow-vehicle-movement-from-players-while-tele.patch delete mode 100644 patches/server/0671-Fix-swamp-hut-cat-generation-deadlock.patch delete mode 100644 patches/server/0672-Don-t-allow-vehicle-movement-from-players-while-tele.patch create mode 100644 patches/server/0672-Implement-getComputedBiome-API.patch delete mode 100644 patches/server/0673-Implement-getComputedBiome-API.patch create mode 100644 patches/server/0673-Make-some-itemstacks-nonnull.patch create mode 100644 patches/server/0674-Implement-enchantWithLevels-API.patch delete mode 100644 patches/server/0674-Make-some-itemstacks-nonnull.patch create mode 100644 patches/server/0675-Fix-saving-in-unloadWorld.patch delete mode 100644 patches/server/0675-Implement-enchantWithLevels-API.patch create mode 100644 patches/server/0676-Buffer-OOB-setBlock-calls.patch delete mode 100644 patches/server/0676-Fix-saving-in-unloadWorld.patch create mode 100644 patches/server/0677-Add-TameableDeathMessageEvent.patch delete mode 100644 patches/server/0677-Buffer-OOB-setBlock-calls.patch delete mode 100644 patches/server/0678-Add-TameableDeathMessageEvent.patch create mode 100644 patches/server/0678-Fix-new-block-data-for-EntityChangeBlockEvent.patch delete mode 100644 patches/server/0679-Fix-new-block-data-for-EntityChangeBlockEvent.patch create mode 100644 patches/server/0679-fix-player-loottables-running-when-mob-loot-gamerule.patch create mode 100644 patches/server/0680-Ensure-entity-passenger-world-matches-ridden-entity.patch delete mode 100644 patches/server/0680-fix-player-loottables-running-when-mob-loot-gamerule.patch create mode 100644 patches/server/0681-Cache-resource-keys-and-optimize-reference-Holder-ta.patch delete mode 100644 patches/server/0681-Ensure-entity-passenger-world-matches-ridden-entity.patch create mode 100644 patches/server/0682-Allow-changing-the-EnderDragon-podium.patch delete mode 100644 patches/server/0682-Cache-resource-keys-and-optimize-reference-Holder-ta.patch delete mode 100644 patches/server/0683-Allow-changing-the-EnderDragon-podium.patch create mode 100644 patches/server/0683-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch delete mode 100644 patches/server/0684-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch create mode 100644 patches/server/0684-Prevent-tile-entity-copies-loading-chunks.patch delete mode 100644 patches/server/0685-Prevent-tile-entity-copies-loading-chunks.patch create mode 100644 patches/server/0685-Use-username-instead-of-display-name-in-PlayerList-g.patch create mode 100644 patches/server/0686-Expand-PlayerItemDamageEvent.patch delete mode 100644 patches/server/0686-Use-username-instead-of-display-name-in-PlayerList-g.patch delete mode 100644 patches/server/0687-Expand-PlayerItemDamageEvent.patch create mode 100644 patches/server/0687-WorldCreator-keepSpawnLoaded.patch create mode 100644 patches/server/0688-Fix-CME-in-CraftPersistentDataTypeRegistry.patch delete mode 100644 patches/server/0688-WorldCreator-keepSpawnLoaded.patch delete mode 100644 patches/server/0689-Fix-CME-in-CraftPersistentDataTypeRegistry.patch create mode 100644 patches/server/0689-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch create mode 100644 patches/server/0690-Add-EntityDyeEvent-and-CollarColorable-interface.patch delete mode 100644 patches/server/0690-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch delete mode 100644 patches/server/0691-Add-EntityDyeEvent-and-CollarColorable-interface.patch create mode 100644 patches/server/0691-Fire-CauldronLevelChange-on-initial-fill.patch delete mode 100644 patches/server/0692-Fire-CauldronLevelChange-on-initial-fill.patch create mode 100644 patches/server/0692-fix-powder-snow-cauldrons-not-turning-to-water.patch create mode 100644 patches/server/0693-Add-PlayerStopUsingItemEvent.patch delete mode 100644 patches/server/0693-fix-powder-snow-cauldrons-not-turning-to-water.patch delete mode 100644 patches/server/0694-Add-PlayerStopUsingItemEvent.patch create mode 100644 patches/server/0694-Don-t-tick-markers.patch delete mode 100644 patches/server/0695-Don-t-tick-markers.patch create mode 100644 patches/server/0695-Expand-FallingBlock-API.patch create mode 100644 patches/server/0696-Add-support-for-Proxy-Protocol.patch delete mode 100644 patches/server/0696-Expand-FallingBlock-API.patch delete mode 100644 patches/server/0697-Add-support-for-Proxy-Protocol.patch create mode 100644 patches/server/0697-Fix-OfflinePlayer-getBedSpawnLocation.patch create mode 100644 patches/server/0698-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch delete mode 100644 patches/server/0698-Fix-OfflinePlayer-getBedSpawnLocation.patch delete mode 100644 patches/server/0699-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch create mode 100644 patches/server/0699-Sanitize-sent-BlockEntity-NBT.patch create mode 100644 patches/server/0700-Disable-component-selector-resolving-in-books-by-def.patch delete mode 100644 patches/server/0700-Sanitize-sent-BlockEntity-NBT.patch delete mode 100644 patches/server/0701-Disable-component-selector-resolving-in-books-by-def.patch create mode 100644 patches/server/0701-Prevent-entity-loading-causing-async-lookups.patch delete mode 100644 patches/server/0702-Prevent-entity-loading-causing-async-lookups.patch create mode 100644 patches/server/0702-Throw-exception-on-world-create-while-being-ticked.patch create mode 100644 patches/server/0703-Dont-resent-entity-on-art-update.patch delete mode 100644 patches/server/0703-Throw-exception-on-world-create-while-being-ticked.patch create mode 100644 patches/server/0704-Add-WardenAngerChangeEvent.patch delete mode 100644 patches/server/0704-Dont-resent-entity-on-art-update.patch delete mode 100644 patches/server/0705-Add-WardenAngerChangeEvent.patch create mode 100644 patches/server/0705-Add-option-for-strict-advancement-dimension-checks.patch create mode 100644 patches/server/0706-Add-missing-important-BlockStateListPopulator-method.patch delete mode 100644 patches/server/0706-Add-option-for-strict-advancement-dimension-checks.patch delete mode 100644 patches/server/0707-Add-missing-important-BlockStateListPopulator-method.patch create mode 100644 patches/server/0707-Nameable-Banner-API.patch create mode 100644 patches/server/0708-Don-t-broadcast-messages-to-command-blocks.patch delete mode 100644 patches/server/0708-Nameable-Banner-API.patch delete mode 100644 patches/server/0709-Don-t-broadcast-messages-to-command-blocks.patch create mode 100644 patches/server/0709-Prevent-empty-items-from-being-added-to-world.patch create mode 100644 patches/server/0710-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch delete mode 100644 patches/server/0710-Prevent-empty-items-from-being-added-to-world.patch create mode 100644 patches/server/0711-Add-Player-getFishHook.patch delete mode 100644 patches/server/0711-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch delete mode 100644 patches/server/0712-Add-Player-getFishHook.patch create mode 100644 patches/server/0712-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch create mode 100644 patches/server/0713-Add-various-missing-EntityDropItemEvent-calls.patch delete mode 100644 patches/server/0713-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch delete mode 100644 patches/server/0714-Add-various-missing-EntityDropItemEvent-calls.patch create mode 100644 patches/server/0714-Fix-Bee-flower-NPE.patch delete mode 100644 patches/server/0715-Fix-Bee-flower-NPE.patch create mode 100644 patches/server/0715-More-Teleport-API.patch create mode 100644 patches/server/0716-Add-EntityPortalReadyEvent.patch delete mode 100644 patches/server/0716-More-Teleport-API.patch delete mode 100644 patches/server/0717-Add-EntityPortalReadyEvent.patch create mode 100644 patches/server/0717-Don-t-use-level-random-in-entity-constructors.patch delete mode 100644 patches/server/0718-Don-t-use-level-random-in-entity-constructors.patch create mode 100644 patches/server/0718-Send-block-entities-after-destroy-prediction.patch delete mode 100644 patches/server/0719-Send-block-entities-after-destroy-prediction.patch create mode 100644 patches/server/0719-Warn-on-plugins-accessing-faraway-chunks.patch create mode 100644 patches/server/0720-Custom-Chat-Completion-Suggestions-API.patch delete mode 100644 patches/server/0720-Warn-on-plugins-accessing-faraway-chunks.patch create mode 100644 patches/server/0721-Add-and-fix-missing-BlockFadeEvents.patch delete mode 100644 patches/server/0721-Custom-Chat-Completion-Suggestions-API.patch delete mode 100644 patches/server/0722-Add-and-fix-missing-BlockFadeEvents.patch create mode 100644 patches/server/0722-Collision-API.patch delete mode 100644 patches/server/0723-Collision-API.patch create mode 100644 patches/server/0723-Fix-suggest-command-message-for-brigadier-syntax-exc.patch create mode 100644 patches/server/0724-Block-Ticking-API.patch delete mode 100644 patches/server/0724-Fix-suggest-command-message-for-brigadier-syntax-exc.patch create mode 100644 patches/server/0725-Add-Velocity-IP-Forwarding-Support.patch delete mode 100644 patches/server/0725-Block-Ticking-API.patch create mode 100644 patches/server/0726-Add-NamespacedKey-biome-methods.patch delete mode 100644 patches/server/0726-Add-Velocity-IP-Forwarding-Support.patch delete mode 100644 patches/server/0727-Add-NamespacedKey-biome-methods.patch create mode 100644 patches/server/0727-Fix-plugin-loggers-on-server-shutdown.patch delete mode 100644 patches/server/0728-Fix-plugin-loggers-on-server-shutdown.patch create mode 100644 patches/server/0728-Stop-large-look-changes-from-crashing-the-server.patch create mode 100644 patches/server/0729-Fire-EntityChangeBlockEvent-in-more-places.patch delete mode 100644 patches/server/0729-Stop-large-look-changes-from-crashing-the-server.patch delete mode 100644 patches/server/0730-Fire-EntityChangeBlockEvent-in-more-places.patch create mode 100644 patches/server/0730-Missing-eating-regain-reason.patch delete mode 100644 patches/server/0731-Missing-eating-regain-reason.patch create mode 100644 patches/server/0731-Missing-effect-cause.patch create mode 100644 patches/server/0732-Added-byte-array-serialization-deserialization-for-P.patch delete mode 100644 patches/server/0732-Missing-effect-cause.patch delete mode 100644 patches/server/0733-Added-byte-array-serialization-deserialization-for-P.patch create mode 100644 patches/server/0733-Call-BlockPhysicsEvent-more-often.patch delete mode 100644 patches/server/0734-Call-BlockPhysicsEvent-more-often.patch create mode 100644 patches/server/0734-Configurable-chat-thread-limit.patch delete mode 100644 patches/server/0735-Configurable-chat-thread-limit.patch create mode 100644 patches/server/0735-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch delete mode 100644 patches/server/0736-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch create mode 100644 patches/server/0736-fix-Jigsaw-block-kicking-user.patch delete mode 100644 patches/server/0737-fix-Jigsaw-block-kicking-user.patch create mode 100644 patches/server/0737-use-BlockFormEvent-for-mud-converting-into-clay.patch create mode 100644 patches/server/0738-Add-getDrops-to-BlockState.patch delete mode 100644 patches/server/0738-use-BlockFormEvent-for-mud-converting-into-clay.patch delete mode 100644 patches/server/0739-Add-getDrops-to-BlockState.patch create mode 100644 patches/server/0739-Fix-a-bunch-of-vanilla-bugs.patch delete mode 100644 patches/server/0740-Fix-a-bunch-of-vanilla-bugs.patch create mode 100644 patches/server/0740-Remove-unnecessary-onTrackingStart-during-navigation.patch create mode 100644 patches/server/0741-Fix-custom-piglin-loved-items.patch delete mode 100644 patches/server/0741-Remove-unnecessary-onTrackingStart-during-navigation.patch create mode 100644 patches/server/0742-EntityPickupItemEvent-fixes.patch delete mode 100644 patches/server/0742-Fix-custom-piglin-loved-items.patch create mode 100644 patches/server/0743-Correctly-handle-interactions-with-items-on-cooldown.patch delete mode 100644 patches/server/0743-EntityPickupItemEvent-fixes.patch create mode 100644 patches/server/0744-Add-PlayerInventorySlotChangeEvent.patch delete mode 100644 patches/server/0744-Correctly-handle-interactions-with-items-on-cooldown.patch delete mode 100644 patches/server/0745-Add-PlayerInventorySlotChangeEvent.patch create mode 100644 patches/server/0745-Elder-Guardian-appearance-API.patch create mode 100644 patches/server/0746-Add-entity-knockback-API.patch delete mode 100644 patches/server/0746-Elder-Guardian-appearance-API.patch delete mode 100644 patches/server/0747-Add-entity-knockback-API.patch create mode 100644 patches/server/0747-Detect-headless-JREs.patch delete mode 100644 patches/server/0748-Detect-headless-JREs.patch create mode 100644 patches/server/0748-fix-entity-vehicle-collision-event-not-called.patch create mode 100644 patches/server/0749-Add-EntityToggleSitEvent.patch delete mode 100644 patches/server/0749-fix-entity-vehicle-collision-event-not-called.patch delete mode 100644 patches/server/0750-Add-EntityToggleSitEvent.patch create mode 100644 patches/server/0750-Add-fire-tick-delay-option.patch create mode 100644 patches/server/0751-Add-Moving-Piston-API.patch delete mode 100644 patches/server/0751-Add-fire-tick-delay-option.patch delete mode 100644 patches/server/0752-Add-Moving-Piston-API.patch create mode 100644 patches/server/0752-Ignore-impossible-spawn-tick.patch create mode 100644 patches/server/0753-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch delete mode 100644 patches/server/0753-Ignore-impossible-spawn-tick.patch delete mode 100644 patches/server/0754-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch create mode 100644 patches/server/0754-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch create mode 100644 patches/server/0755-Add-PrePlayerAttackEntityEvent.patch delete mode 100644 patches/server/0755-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch delete mode 100644 patches/server/0756-Add-PrePlayerAttackEntityEvent.patch create mode 100644 patches/server/0756-ensure-reset-EnderDragon-boss-event-name.patch create mode 100644 patches/server/0757-Add-Player-Warden-Warning-API.patch delete mode 100644 patches/server/0757-ensure-reset-EnderDragon-boss-event-name.patch delete mode 100644 patches/server/0758-Add-Player-Warden-Warning-API.patch create mode 100644 patches/server/0758-More-vanilla-friendly-methods-to-update-trades.patch create mode 100644 patches/server/0759-Add-paper-dumplisteners-command.patch delete mode 100644 patches/server/0759-More-vanilla-friendly-methods-to-update-trades.patch delete mode 100644 patches/server/0760-Add-paper-dumplisteners-command.patch create mode 100644 patches/server/0760-check-global-player-list-where-appropriate.patch create mode 100644 patches/server/0761-Fix-async-entity-add-due-to-fungus-trees.patch delete mode 100644 patches/server/0761-check-global-player-list-where-appropriate.patch delete mode 100644 patches/server/0762-Fix-async-entity-add-due-to-fungus-trees.patch create mode 100644 patches/server/0762-ItemStack-damage-API.patch create mode 100644 patches/server/0763-Friction-API.patch delete mode 100644 patches/server/0763-ItemStack-damage-API.patch create mode 100644 patches/server/0764-Ability-to-control-player-s-insomnia-and-phantoms.patch delete mode 100644 patches/server/0764-Friction-API.patch delete mode 100644 patches/server/0765-Ability-to-control-player-s-insomnia-and-phantoms.patch create mode 100644 patches/server/0765-Fix-premature-player-kicks-on-shutdown.patch delete mode 100644 patches/server/0766-Fix-premature-player-kicks-on-shutdown.patch create mode 100644 patches/server/0766-Sync-offhand-slot-in-menus.patch create mode 100644 patches/server/0767-Player-Entity-Tracking-Events.patch delete mode 100644 patches/server/0767-Sync-offhand-slot-in-menus.patch create mode 100644 patches/server/0768-Limit-pet-look-distance.patch delete mode 100644 patches/server/0768-Player-Entity-Tracking-Events.patch delete mode 100644 patches/server/0769-Limit-pet-look-distance.patch create mode 100644 patches/server/0769-fix-Instruments.patch create mode 100644 patches/server/0770-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch delete mode 100644 patches/server/0770-fix-Instruments.patch create mode 100644 patches/server/0771-Add-BlockLockCheckEvent.patch delete mode 100644 patches/server/0771-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch delete mode 100644 patches/server/0772-Add-BlockLockCheckEvent.patch create mode 100644 patches/server/0772-Add-Sneaking-API-for-Entities.patch delete mode 100644 patches/server/0773-Add-Sneaking-API-for-Entities.patch create mode 100644 patches/server/0773-Improve-logging-and-errors.patch create mode 100644 patches/server/0774-Improve-PortalEvents.patch delete mode 100644 patches/server/0774-Improve-logging-and-errors.patch create mode 100644 patches/server/0775-Add-config-option-for-spider-worldborder-climbing.patch delete mode 100644 patches/server/0775-Improve-PortalEvents.patch delete mode 100644 patches/server/0776-Add-config-option-for-spider-worldborder-climbing.patch create mode 100644 patches/server/0776-Add-missing-SpigotConfig-logCommands-check.patch delete mode 100644 patches/server/0777-Add-missing-SpigotConfig-logCommands-check.patch create mode 100644 patches/server/0777-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch delete mode 100644 patches/server/0778-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch create mode 100644 patches/server/0778-Flying-Fall-Damage.patch create mode 100644 patches/server/0779-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch delete mode 100644 patches/server/0779-Flying-Fall-Damage.patch delete mode 100644 patches/server/0780-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch create mode 100644 patches/server/0780-config-for-disabling-entity-tag-tags.patch create mode 100644 patches/server/0781-Use-single-player-info-update-packet-on-join.patch delete mode 100644 patches/server/0781-config-for-disabling-entity-tag-tags.patch create mode 100644 patches/server/0782-Correctly-shrink-items-during-EntityResurrectEvent.patch delete mode 100644 patches/server/0782-Use-single-player-info-update-packet-on-join.patch delete mode 100644 patches/server/0783-Correctly-shrink-items-during-EntityResurrectEvent.patch create mode 100644 patches/server/0783-Win-Screen-API.patch create mode 100644 patches/server/0784-Remove-CraftItemStack-setAmount-null-assignment.patch delete mode 100644 patches/server/0784-Win-Screen-API.patch create mode 100644 patches/server/0785-Fix-force-opening-enchantment-tables.patch delete mode 100644 patches/server/0785-Remove-CraftItemStack-setAmount-null-assignment.patch create mode 100644 patches/server/0786-Add-Entity-Body-Yaw-API.patch delete mode 100644 patches/server/0786-Fix-force-opening-enchantment-tables.patch delete mode 100644 patches/server/0787-Add-Entity-Body-Yaw-API.patch create mode 100644 patches/server/0787-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch create mode 100644 patches/server/0788-Add-EntityFertilizeEggEvent.patch delete mode 100644 patches/server/0788-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch delete mode 100644 patches/server/0789-Add-EntityFertilizeEggEvent.patch create mode 100644 patches/server/0789-Fix-HumanEntity-drop-not-updating-the-client-inv.patch create mode 100644 patches/server/0790-Add-CompostItemEvent-and-EntityCompostItemEvent.patch delete mode 100644 patches/server/0790-Fix-HumanEntity-drop-not-updating-the-client-inv.patch delete mode 100644 patches/server/0791-Add-CompostItemEvent-and-EntityCompostItemEvent.patch create mode 100644 patches/server/0791-Correctly-handle-ArmorStand-invisibility.patch delete mode 100644 patches/server/0792-Correctly-handle-ArmorStand-invisibility.patch create mode 100644 patches/server/0792-Fix-advancement-triggers-for-entity-damage.patch delete mode 100644 patches/server/0793-Fix-advancement-triggers-for-entity-damage.patch create mode 100644 patches/server/0793-Fix-text-display-error-on-spawn.patch create mode 100644 patches/server/0794-Fix-inventories-returning-null-Locations.patch delete mode 100644 patches/server/0794-Fix-text-display-error-on-spawn.patch create mode 100644 patches/server/0795-Add-Shearable-API.patch delete mode 100644 patches/server/0795-Fix-inventories-returning-null-Locations.patch delete mode 100644 patches/server/0796-Add-Shearable-API.patch create mode 100644 patches/server/0796-Fix-SpawnEggMeta-get-setSpawnedType.patch delete mode 100644 patches/server/0797-Fix-SpawnEggMeta-get-setSpawnedType.patch create mode 100644 patches/server/0797-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch delete mode 100644 patches/server/0798-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch create mode 100644 patches/server/0798-Treat-sequence-violations-like-they-should-be.patch create mode 100644 patches/server/0799-Prevent-causing-expired-keys-from-impacting-new-join.patch delete mode 100644 patches/server/0799-Treat-sequence-violations-like-they-should-be.patch create mode 100644 patches/server/0800-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch delete mode 100644 patches/server/0800-Prevent-causing-expired-keys-from-impacting-new-join.patch delete mode 100644 patches/server/0801-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch create mode 100644 patches/server/0801-Use-array-for-gamerule-storage.patch create mode 100644 patches/server/0802-Fix-a-couple-of-upstream-bed-issues.patch delete mode 100644 patches/server/0802-Use-array-for-gamerule-storage.patch delete mode 100644 patches/server/0803-Fix-a-couple-of-upstream-bed-issues.patch create mode 100644 patches/server/0803-Fix-demo-flag-not-enabling-demo-mode.patch create mode 100644 patches/server/0804-Add-Mob-Experience-reward-API.patch delete mode 100644 patches/server/0804-Fix-demo-flag-not-enabling-demo-mode.patch delete mode 100644 patches/server/0805-Add-Mob-Experience-reward-API.patch create mode 100644 patches/server/0805-Break-redstone-on-top-of-trap-doors-early.patch create mode 100644 patches/server/0806-Avoid-Lazy-Initialization-for-Enum-Fields.patch delete mode 100644 patches/server/0806-Break-redstone-on-top-of-trap-doors-early.patch delete mode 100644 patches/server/0807-Avoid-Lazy-Initialization-for-Enum-Fields.patch create mode 100644 patches/server/0807-More-accurate-isInOpenWater-impl.patch create mode 100644 patches/server/0808-Expand-PlayerItemMendEvent.patch delete mode 100644 patches/server/0808-More-accurate-isInOpenWater-impl.patch delete mode 100644 patches/server/0809-Expand-PlayerItemMendEvent.patch create mode 100644 patches/server/0809-Refresh-ProjectileSource-for-projectiles.patch create mode 100644 patches/server/0810-Add-transient-modifier-API.patch delete mode 100644 patches/server/0810-Refresh-ProjectileSource-for-projectiles.patch delete mode 100644 patches/server/0811-Add-transient-modifier-API.patch create mode 100644 patches/server/0811-Fix-block-place-logic.patch delete mode 100644 patches/server/0812-Fix-block-place-logic.patch create mode 100644 patches/server/0812-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch create mode 100644 patches/server/0813-Call-BlockGrowEvent-for-missing-blocks.patch delete mode 100644 patches/server/0813-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch delete mode 100644 patches/server/0814-Call-BlockGrowEvent-for-missing-blocks.patch create mode 100644 patches/server/0814-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch delete mode 100644 patches/server/0815-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch create mode 100644 patches/server/0815-fix-MapLike-spam-for-missing-key-selector.patch create mode 100644 patches/server/0816-Fix-sniffer-removeExploredLocation.patch delete mode 100644 patches/server/0816-fix-MapLike-spam-for-missing-key-selector.patch create mode 100644 patches/server/0817-Add-method-to-remove-all-active-potion-effects.patch delete mode 100644 patches/server/0817-Fix-sniffer-removeExploredLocation.patch create mode 100644 patches/server/0818-Add-event-for-player-editing-sign.patch delete mode 100644 patches/server/0818-Add-method-to-remove-all-active-potion-effects.patch delete mode 100644 patches/server/0819-Add-event-for-player-editing-sign.patch create mode 100644 patches/server/0819-Only-tick-item-frames-if-players-can-see-it.patch create mode 100644 patches/server/0820-Fix-cmd-permission-levels-for-command-blocks.patch delete mode 100644 patches/server/0820-Only-tick-item-frames-if-players-can-see-it.patch create mode 100644 patches/server/0821-Add-option-to-disable-block-updates.patch delete mode 100644 patches/server/0821-Fix-cmd-permission-levels-for-command-blocks.patch delete mode 100644 patches/server/0822-Add-option-to-disable-block-updates.patch create mode 100644 patches/server/0822-Call-missing-BlockDispenseEvent.patch delete mode 100644 patches/server/0823-Call-missing-BlockDispenseEvent.patch create mode 100644 patches/server/0823-Don-t-load-chunks-for-supporting-block-checks.patch delete mode 100644 patches/server/0824-Don-t-load-chunks-for-supporting-block-checks.patch create mode 100644 patches/server/0824-Optimize-player-lookups-for-beacons.patch create mode 100644 patches/server/0825-More-Sign-Block-API.patch delete mode 100644 patches/server/0825-Optimize-player-lookups-for-beacons.patch delete mode 100644 patches/server/0826-More-Sign-Block-API.patch create mode 100644 patches/server/0826-fix-item-meta-for-tadpole-buckets.patch create mode 100644 patches/server/0827-Fix-BanList-API.patch delete mode 100644 patches/server/0827-fix-item-meta-for-tadpole-buckets.patch create mode 100644 patches/server/0828-Determine-lava-and-water-fluid-explosion-resistance-.patch delete mode 100644 patches/server/0828-Fix-BanList-API.patch delete mode 100644 patches/server/0829-Determine-lava-and-water-fluid-explosion-resistance-.patch create mode 100644 patches/server/0829-Fix-possible-NPE-on-painting-creation.patch delete mode 100644 patches/server/0830-Fix-possible-NPE-on-painting-creation.patch create mode 100644 patches/server/0830-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch create mode 100644 patches/server/0831-ExperienceOrb-should-call-EntitySpawnEvent.patch delete mode 100644 patches/server/0831-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch delete mode 100644 patches/server/0832-ExperienceOrb-should-call-EntitySpawnEvent.patch create mode 100644 patches/server/0832-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch create mode 100644 patches/server/0833-Add-whitelist-events.patch delete mode 100644 patches/server/0833-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch delete mode 100644 patches/server/0834-Add-whitelist-events.patch create mode 100644 patches/server/0834-Implement-PlayerFailMoveEvent.patch create mode 100644 patches/server/0835-Folia-scheduler-and-owned-region-API.patch delete mode 100644 patches/server/0835-Implement-PlayerFailMoveEvent.patch delete mode 100644 patches/server/0836-Folia-scheduler-and-owned-region-API.patch create mode 100644 patches/server/0836-Only-erase-allay-memory-on-non-item-targets.patch create mode 100644 patches/server/0837-Fix-rotation-when-spawning-display-entities.patch delete mode 100644 patches/server/0837-Only-erase-allay-memory-on-non-item-targets.patch delete mode 100644 patches/server/0838-Fix-rotation-when-spawning-display-entities.patch create mode 100644 patches/server/0838-Only-capture-actual-tree-growth.patch delete mode 100644 patches/server/0839-Only-capture-actual-tree-growth.patch create mode 100644 patches/server/0839-Use-correct-source-for-mushroom-block-spread-event.patch create mode 100644 patches/server/0840-Respect-randomizeData-on-more-entities-when-spawning.patch delete mode 100644 patches/server/0840-Use-correct-source-for-mushroom-block-spread-event.patch delete mode 100644 patches/server/0841-Respect-randomizeData-on-more-entities-when-spawning.patch create mode 100644 patches/server/0841-Use-correct-seed-on-api-world-load.patch create mode 100644 patches/server/0842-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch delete mode 100644 patches/server/0842-Use-correct-seed-on-api-world-load.patch create mode 100644 patches/server/0843-Cache-map-ids-on-item-frames.patch delete mode 100644 patches/server/0843-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch create mode 100644 patches/server/0844-API-for-updating-recipes-on-clients.patch delete mode 100644 patches/server/0844-Cache-map-ids-on-item-frames.patch delete mode 100644 patches/server/0845-API-for-updating-recipes-on-clients.patch create mode 100644 patches/server/0845-Fix-custom-statistic-criteria-creation.patch create mode 100644 patches/server/0846-Bandaid-fix-for-Effect.patch delete mode 100644 patches/server/0846-Fix-custom-statistic-criteria-creation.patch delete mode 100644 patches/server/0847-Bandaid-fix-for-Effect.patch create mode 100644 patches/server/0847-SculkCatalyst-bloom-API.patch create mode 100644 patches/server/0848-API-for-an-entity-s-scoreboard-name.patch delete mode 100644 patches/server/0848-SculkCatalyst-bloom-API.patch delete mode 100644 patches/server/0849-API-for-an-entity-s-scoreboard-name.patch create mode 100644 patches/server/0849-Deprecate-and-replace-methods-with-old-StructureType.patch delete mode 100644 patches/server/0850-Deprecate-and-replace-methods-with-old-StructureType.patch create mode 100644 patches/server/0850-Don-t-tab-complete-namespaced-commands-if-send-names.patch delete mode 100644 patches/server/0851-Don-t-tab-complete-namespaced-commands-if-send-names.patch create mode 100644 patches/server/0851-Properly-handle-BlockBreakEvent-isDropItems.patch create mode 100644 patches/server/0852-Fire-entity-death-event-for-ender-dragon.patch delete mode 100644 patches/server/0852-Properly-handle-BlockBreakEvent-isDropItems.patch create mode 100644 patches/server/0853-Configurable-entity-tracking-range-by-Y-coordinate.patch delete mode 100644 patches/server/0853-Fire-entity-death-event-for-ender-dragon.patch create mode 100644 patches/server/0854-Add-Listing-API-for-Player.patch delete mode 100644 patches/server/0854-Configurable-entity-tracking-range-by-Y-coordinate.patch delete mode 100644 patches/server/0855-Add-Listing-API-for-Player.patch create mode 100644 patches/server/0855-Configurable-Region-Compression-Format.patch create mode 100644 patches/server/0856-Add-BlockFace-to-BlockDamageEvent.patch delete mode 100644 patches/server/0856-Configurable-Region-Compression-Format.patch delete mode 100644 patches/server/0857-Add-BlockFace-to-BlockDamageEvent.patch create mode 100644 patches/server/0857-Fix-NPE-on-Boat-getStatus.patch create mode 100644 patches/server/0858-Expand-Pose-API.patch delete mode 100644 patches/server/0858-Fix-NPE-on-Boat-getStatus.patch delete mode 100644 patches/server/0859-Expand-Pose-API.patch create mode 100644 patches/server/0859-More-DragonBattle-API.patch create mode 100644 patches/server/0860-Add-PlayerPickItemEvent.patch delete mode 100644 patches/server/0860-More-DragonBattle-API.patch delete mode 100644 patches/server/0861-Add-PlayerPickItemEvent.patch create mode 100644 patches/server/0861-Allow-trident-custom-damage.patch delete mode 100644 patches/server/0862-Allow-trident-custom-damage.patch create mode 100644 patches/server/0862-Expose-hand-in-BlockCanBuildEvent.patch delete mode 100644 patches/server/0863-Expose-hand-in-BlockCanBuildEvent.patch create mode 100644 patches/server/0863-Optimize-nearest-structure-border-iteration.patch create mode 100644 patches/server/0864-Implement-OfflinePlayer-isConnected.patch delete mode 100644 patches/server/0864-Optimize-nearest-structure-border-iteration.patch create mode 100644 patches/server/0865-Fix-slot-desync.patch delete mode 100644 patches/server/0865-Implement-OfflinePlayer-isConnected.patch create mode 100644 patches/server/0866-Add-titleOverride-to-InventoryOpenEvent.patch delete mode 100644 patches/server/0866-Fix-slot-desync.patch delete mode 100644 patches/server/0867-Add-titleOverride-to-InventoryOpenEvent.patch create mode 100644 patches/server/0867-Configure-sniffer-egg-hatch-time.patch delete mode 100644 patches/server/0868-Configure-sniffer-egg-hatch-time.patch create mode 100644 patches/server/0868-Do-crystal-portal-proximity-check-before-entity-look.patch delete mode 100644 patches/server/0869-Do-crystal-portal-proximity-check-before-entity-look.patch create mode 100644 patches/server/0869-Skip-POI-finding-if-stuck-in-vehicle.patch create mode 100644 patches/server/0870-Add-slot-sanity-checks-in-container-clicks.patch delete mode 100644 patches/server/0870-Skip-POI-finding-if-stuck-in-vehicle.patch delete mode 100644 patches/server/0871-Add-slot-sanity-checks-in-container-clicks.patch create mode 100644 patches/server/0871-Call-BlockRedstoneEvents-for-lecterns.patch create mode 100644 patches/server/0872-Allow-proper-checking-of-empty-item-stacks.patch delete mode 100644 patches/server/0872-Call-BlockRedstoneEvents-for-lecterns.patch delete mode 100644 patches/server/0873-Allow-proper-checking-of-empty-item-stacks.patch create mode 100644 patches/server/0873-Fix-silent-equipment-change-for-mobs.patch delete mode 100644 patches/server/0874-Fix-silent-equipment-change-for-mobs.patch create mode 100644 patches/server/0874-Fix-spigot-s-Forced-Stats.patch create mode 100644 patches/server/0875-Add-missing-InventoryHolders-to-inventories.patch delete mode 100644 patches/server/0875-Fix-spigot-s-Forced-Stats.patch delete mode 100644 patches/server/0876-Add-missing-InventoryHolders-to-inventories.patch create mode 100644 patches/server/0876-Do-not-read-tile-entities-in-chunks-that-are-positio.patch create mode 100644 patches/server/0877-Add-missing-logs-for-log-ips-config-option.patch delete mode 100644 patches/server/0877-Do-not-read-tile-entities-in-chunks-that-are-positio.patch delete mode 100644 patches/server/0878-Add-missing-logs-for-log-ips-config-option.patch create mode 100644 patches/server/0878-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch create mode 100644 patches/server/0879-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch delete mode 100644 patches/server/0879-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch delete mode 100644 patches/server/0880-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch create mode 100644 patches/server/0880-Fix-team-sidebar-objectives-not-being-cleared.patch create mode 100644 patches/server/0881-Fix-missing-map-initialize-event-call.patch delete mode 100644 patches/server/0881-Fix-team-sidebar-objectives-not-being-cleared.patch delete mode 100644 patches/server/0882-Fix-missing-map-initialize-event-call.patch create mode 100644 patches/server/0882-Update-entity-data-when-attaching-firework-to-entity.patch create mode 100644 patches/server/0883-Fix-UnsafeValues-loadAdvancement.patch delete mode 100644 patches/server/0883-Update-entity-data-when-attaching-firework-to-entity.patch create mode 100644 patches/server/0884-Add-player-idle-duration-API.patch delete mode 100644 patches/server/0884-Fix-UnsafeValues-loadAdvancement.patch delete mode 100644 patches/server/0885-Add-player-idle-duration-API.patch create mode 100644 patches/server/0885-Don-t-check-if-we-can-see-non-visible-entities.patch delete mode 100644 patches/server/0886-Don-t-check-if-we-can-see-non-visible-entities.patch create mode 100644 patches/server/0886-Fix-NPE-in-SculkBloomEvent-world-access.patch create mode 100644 patches/server/0887-Allow-null-itemstack-for-Player-sendEquipmentChange.patch delete mode 100644 patches/server/0887-Fix-NPE-in-SculkBloomEvent-world-access.patch delete mode 100644 patches/server/0888-Allow-null-itemstack-for-Player-sendEquipmentChange.patch create mode 100644 patches/server/0888-Optimize-VarInts.patch create mode 100644 patches/server/0889-Add-API-to-get-the-collision-shape-of-a-block-before.patch delete mode 100644 patches/server/0889-Optimize-VarInts.patch delete mode 100644 patches/server/0890-Add-API-to-get-the-collision-shape-of-a-block-before.patch create mode 100644 patches/server/0890-Add-predicate-for-blocks-when-raytracing.patch delete mode 100644 patches/server/0891-Add-predicate-for-blocks-when-raytracing.patch create mode 100644 patches/server/0891-Broadcast-take-item-packets-with-collector-as-source.patch delete mode 100644 patches/server/0892-Broadcast-take-item-packets-with-collector-as-source.patch create mode 100644 patches/server/0892-Expand-LingeringPotion-API.patch delete mode 100644 patches/server/0893-Expand-LingeringPotion-API.patch create mode 100644 patches/server/0893-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch create mode 100644 patches/server/0894-Add-hand-to-fish-event-for-all-player-interactions.patch delete mode 100644 patches/server/0894-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch delete mode 100644 patches/server/0895-Add-hand-to-fish-event-for-all-player-interactions.patch create mode 100644 patches/server/0895-Fix-several-issues-with-EntityBreedEvent.patch create mode 100644 patches/server/0896-Add-UUID-attribute-modifier-API.patch delete mode 100644 patches/server/0896-Fix-several-issues-with-EntityBreedEvent.patch delete mode 100644 patches/server/0897-Add-UUID-attribute-modifier-API.patch create mode 100644 patches/server/0897-Fix-missing-event-call-for-entity-teleport-API.patch delete mode 100644 patches/server/0898-Fix-missing-event-call-for-entity-teleport-API.patch create mode 100644 patches/server/0898-Lazily-create-LootContext-for-criterions.patch create mode 100644 patches/server/0899-Don-t-fire-sync-events-during-worldgen.patch delete mode 100644 patches/server/0899-Lazily-create-LootContext-for-criterions.patch create mode 100644 patches/server/0900-Add-Structure-check-API.patch delete mode 100644 patches/server/0900-Don-t-fire-sync-events-during-worldgen.patch delete mode 100644 patches/server/0901-Add-Structure-check-API.patch create mode 100644 patches/server/0901-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch delete mode 100644 patches/server/0902-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch create mode 100644 patches/server/0902-Restore-vanilla-entity-drops-behavior.patch create mode 100644 patches/server/0903-Dont-resend-blocks-on-interactions.patch delete mode 100644 patches/server/0903-Restore-vanilla-entity-drops-behavior.patch delete mode 100644 patches/server/0904-Dont-resend-blocks-on-interactions.patch create mode 100644 patches/server/0904-add-more-scoreboard-API.patch create mode 100644 patches/server/0905-Improve-Registry.patch delete mode 100644 patches/server/0905-add-more-scoreboard-API.patch create mode 100644 patches/server/0906-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch delete mode 100644 patches/server/0906-Improve-Registry.patch create mode 100644 patches/server/0907-Add-experience-points-API.patch delete mode 100644 patches/server/0907-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch create mode 100644 patches/server/0908-Add-drops-to-shear-events.patch delete mode 100644 patches/server/0908-Add-experience-points-API.patch create mode 100644 patches/server/0909-Add-PlayerShieldDisableEvent.patch delete mode 100644 patches/server/0909-Add-drops-to-shear-events.patch delete mode 100644 patches/server/0910-Add-PlayerShieldDisableEvent.patch create mode 100644 patches/server/0910-Validate-ResourceLocation-in-NBT-reading.patch create mode 100644 patches/server/0911-Properly-handle-experience-dropping-on-block-break.patch delete mode 100644 patches/server/0911-Validate-ResourceLocation-in-NBT-reading.patch create mode 100644 patches/server/0912-Fixup-NamespacedKey-handling.patch delete mode 100644 patches/server/0912-Properly-handle-experience-dropping-on-block-break.patch create mode 100644 patches/server/0913-Expose-LootTable-of-DecoratedPot.patch delete mode 100644 patches/server/0913-Fixup-NamespacedKey-handling.patch delete mode 100644 patches/server/0914-Expose-LootTable-of-DecoratedPot.patch create mode 100644 patches/server/0914-Reduce-allocation-of-Vec3D-by-entity-tracker.patch create mode 100644 patches/server/0915-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch delete mode 100644 patches/server/0915-Reduce-allocation-of-Vec3D-by-entity-tracker.patch delete mode 100644 patches/server/0916-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch create mode 100644 patches/server/0916-Add-ShulkerDuplicateEvent.patch delete mode 100644 patches/server/0917-Add-ShulkerDuplicateEvent.patch create mode 100644 patches/server/0917-Add-api-for-spawn-egg-texture-colors.patch create mode 100644 patches/server/0918-Add-Lifecycle-Event-system.patch delete mode 100644 patches/server/0918-Add-api-for-spawn-egg-texture-colors.patch delete mode 100644 patches/server/0919-Add-Lifecycle-Event-system.patch create mode 100644 patches/server/0919-ItemStack-Tooltip-API.patch create mode 100644 patches/server/0920-Add-getChunkSnapshot-includeLightData-parameter.patch delete mode 100644 patches/server/0920-ItemStack-Tooltip-API.patch create mode 100644 patches/server/0921-Add-FluidState-API.patch delete mode 100644 patches/server/0921-Add-getChunkSnapshot-includeLightData-parameter.patch delete mode 100644 patches/server/0922-Add-FluidState-API.patch create mode 100644 patches/server/0922-add-number-format-api.patch delete mode 100644 patches/server/0923-add-number-format-api.patch create mode 100644 patches/server/0923-improve-BanList-types.patch create mode 100644 patches/server/0924-Expanded-Hopper-API.patch delete mode 100644 patches/server/0924-improve-BanList-types.patch create mode 100644 patches/server/0925-Add-BlockBreakProgressUpdateEvent.patch delete mode 100644 patches/server/0925-Expanded-Hopper-API.patch delete mode 100644 patches/server/0926-Add-BlockBreakProgressUpdateEvent.patch create mode 100644 patches/server/0926-Deprecate-ItemStack-setType.patch create mode 100644 patches/server/0927-Add-CartographyItemEvent.patch delete mode 100644 patches/server/0927-Deprecate-ItemStack-setType.patch delete mode 100644 patches/server/0928-Add-CartographyItemEvent.patch create mode 100644 patches/server/0928-More-Raid-API.patch create mode 100644 patches/server/0929-Add-onboarding-message-for-initial-server-start.patch delete mode 100644 patches/server/0929-More-Raid-API.patch delete mode 100644 patches/server/0930-Add-onboarding-message-for-initial-server-start.patch create mode 100644 patches/server/0930-Configurable-max-block-fluid-ticks.patch delete mode 100644 patches/server/0931-Configurable-max-block-fluid-ticks.patch create mode 100644 patches/server/0931-Fix-bees-aging-inside-hives.patch create mode 100644 patches/server/0932-Disable-memory-reserve-allocating.patch delete mode 100644 patches/server/0932-Fix-bees-aging-inside-hives.patch delete mode 100644 patches/server/0933-Disable-memory-reserve-allocating.patch create mode 100644 patches/server/0933-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch delete mode 100644 patches/server/0934-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch create mode 100644 patches/server/0934-Fix-DamageSource-API.patch delete mode 100644 patches/server/0935-Fix-DamageSource-API.patch create mode 100644 patches/server/0935-Fix-creation-of-invalid-block-entity-during-world-ge.patch delete mode 100644 patches/server/0936-Fix-creation-of-invalid-block-entity-during-world-ge.patch create mode 100644 patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch delete mode 100644 patches/server/0937-Fix-possible-StackOverflowError-for-some-dispenses.patch create mode 100644 patches/server/0937-Improve-tag-parser-handling.patch delete mode 100644 patches/server/0938-Improve-tag-parser-handling.patch create mode 100644 patches/server/0938-Item-Mutation-Fixes.patch delete mode 100644 patches/server/0939-Item-Mutation-Fixes.patch create mode 100644 patches/server/0939-Per-world-ticks-per-spawn-settings.patch delete mode 100644 patches/server/0940-Per-world-ticks-per-spawn-settings.patch create mode 100644 patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch delete mode 100644 patches/server/0941-Properly-track-the-changed-item-from-dispense-events.patch create mode 100644 patches/server/0941-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch create mode 100644 patches/server/0942-Add-config-for-mobs-immune-to-default-effects.patch delete mode 100644 patches/server/0942-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch delete mode 100644 patches/server/0943-Add-config-for-mobs-immune-to-default-effects.patch create mode 100644 patches/server/0943-Deep-clone-nbt-tags-in-PDC.patch delete mode 100644 patches/server/0944-Deep-clone-nbt-tags-in-PDC.patch create mode 100644 patches/server/0944-Support-old-UUID-format-for-NBT.patch create mode 100644 patches/server/0945-Fix-shield-disable-inconsistency.patch delete mode 100644 patches/server/0945-Support-old-UUID-format-for-NBT.patch delete mode 100644 patches/server/0946-Fix-shield-disable-inconsistency.patch create mode 100644 patches/server/0946-Handle-Large-Packets-disconnecting-client.patch create mode 100644 patches/server/0947-Fix-ItemFlags.patch delete mode 100644 patches/server/0947-Handle-Large-Packets-disconnecting-client.patch delete mode 100644 patches/server/0948-Fix-ItemFlags.patch create mode 100644 patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch delete mode 100644 patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch create mode 100644 patches/server/0949-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch delete mode 100644 patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch create mode 100644 patches/server/0950-improve-checking-handled-tags-in-itemmeta.patch create mode 100644 patches/server/0951-Expose-hasColor-to-leather-armor.patch delete mode 100644 patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch create mode 100644 patches/server/0952-Added-API-to-get-player-ha-proxy-address.patch delete mode 100644 patches/server/0952-Expose-hasColor-to-leather-armor.patch delete mode 100644 patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch create mode 100644 patches/server/0953-General-ItemMeta-fixes.patch delete mode 100644 patches/server/0954-General-ItemMeta-fixes.patch create mode 100644 patches/server/0954-More-Chest-Block-API.patch delete mode 100644 patches/server/0955-More-Chest-Block-API.patch create mode 100644 patches/server/0955-Print-data-component-type-on-encoding-error.patch create mode 100644 patches/server/0956-Brigadier-based-command-API.patch delete mode 100644 patches/server/0956-Print-data-component-type-on-encoding-error.patch delete mode 100644 patches/server/0957-Brigadier-based-command-API.patch create mode 100644 patches/server/0957-Fix-issues-with-Recipe-API.patch create mode 100644 patches/server/0958-Fix-equipment-slot-and-group-API.patch delete mode 100644 patches/server/0958-Fix-issues-with-Recipe-API.patch create mode 100644 patches/server/0959-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch delete mode 100644 patches/server/0959-Fix-equipment-slot-and-group-API.patch delete mode 100644 patches/server/0960-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch create mode 100644 patches/server/0960-Prevent-sending-oversized-item-data-in-equipment-and.patch create mode 100644 patches/server/0961-Prevent-NPE-if-hooked-entity-was-cleared.patch delete mode 100644 patches/server/0961-Prevent-sending-oversized-item-data-in-equipment-and.patch create mode 100644 patches/server/0962-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch delete mode 100644 patches/server/0962-Prevent-NPE-if-hooked-entity-was-cleared.patch create mode 100644 patches/server/0963-Add-missing-fishing-event-state.patch delete mode 100644 patches/server/0963-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch delete mode 100644 patches/server/0964-Add-missing-fishing-event-state.patch create mode 100644 patches/server/0964-Deprecate-InvAction-HOTBAR_MOVE_AND_READD.patch delete mode 100644 patches/server/0965-Deprecate-InvAction-HOTBAR_MOVE_AND_READD.patch create mode 100644 patches/server/0965-Fix-sending-disconnect-packet-in-phases-where-it-doe.patch create mode 100644 patches/server/0966-Adopt-MaterialRerouting.patch delete mode 100644 patches/server/0966-Fix-sending-disconnect-packet-in-phases-where-it-doe.patch delete mode 100644 patches/server/0967-Adopt-MaterialRerouting.patch create mode 100644 patches/server/0967-Suspicious-Effect-Entry-API.patch delete mode 100644 patches/server/0968-Suspicious-Effect-Entry-API.patch create mode 100644 patches/server/0968-check-if-itemstack-is-stackable-first.patch create mode 100644 patches/server/0969-Fix-removing-recipes-from-RecipeIterator.patch delete mode 100644 patches/server/0969-check-if-itemstack-is-stackable-first.patch create mode 100644 patches/server/0970-Configurable-damage-tick-when-blocking-with-shield.patch delete mode 100644 patches/server/0970-Fix-removing-recipes-from-RecipeIterator.patch delete mode 100644 patches/server/0971-Configurable-damage-tick-when-blocking-with-shield.patch create mode 100644 patches/server/0971-Properly-remove-the-experimental-smithing-inventory-.patch delete mode 100644 patches/server/0972-Properly-remove-the-experimental-smithing-inventory-.patch create mode 100644 patches/server/0972-disable-forced-empty-world-ticks.patch create mode 100644 patches/server/0973-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch delete mode 100644 patches/server/0973-disable-forced-empty-world-ticks.patch create mode 100644 patches/server/0974-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch delete mode 100644 patches/server/0974-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch delete mode 100644 patches/server/0975-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch create mode 100644 patches/server/0975-Optimize-Network-Manager-and-add-advanced-packet-sup.patch create mode 100644 patches/server/0976-Allow-Saving-of-Oversized-Chunks.patch delete mode 100644 patches/server/0976-Optimize-Network-Manager-and-add-advanced-packet-sup.patch delete mode 100644 patches/server/0977-Allow-Saving-of-Oversized-Chunks.patch create mode 100644 patches/server/0977-Flat-bedrock-generator-settings.patch create mode 100644 patches/server/0978-Entity-Activation-Range-2.0.patch delete mode 100644 patches/server/0978-Flat-bedrock-generator-settings.patch create mode 100644 patches/server/0979-Anti-Xray.patch delete mode 100644 patches/server/0979-Entity-Activation-Range-2.0.patch delete mode 100644 patches/server/0980-Anti-Xray.patch create mode 100644 patches/server/0980-Use-Velocity-compression-and-cipher-natives.patch create mode 100644 patches/server/0981-Optimize-Collision-to-not-load-chunks.patch delete mode 100644 patches/server/0981-Use-Velocity-compression-and-cipher-natives.patch delete mode 100644 patches/server/0982-Optimize-Collision-to-not-load-chunks.patch create mode 100644 patches/server/0982-Optimize-GoalSelector-Goal.Flag-Set-operations.patch delete mode 100644 patches/server/0983-Optimize-GoalSelector-Goal.Flag-Set-operations.patch create mode 100644 patches/server/0983-Optimize-Hoppers.patch delete mode 100644 patches/server/0984-Optimize-Hoppers.patch create mode 100644 patches/server/0984-Optimize-Voxel-Shape-Merging.patch create mode 100644 patches/server/0985-Optimize-Bit-Operations-by-inlining.patch delete mode 100644 patches/server/0985-Optimize-Voxel-Shape-Merging.patch delete mode 100644 patches/server/0986-Optimize-Bit-Operations-by-inlining.patch create mode 100644 patches/server/0986-Remove-streams-from-hot-code.patch create mode 100644 patches/server/0987-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch delete mode 100644 patches/server/0987-Remove-streams-from-hot-code.patch create mode 100644 patches/server/0988-Fix-entity-type-tags-suggestions-in-selectors.patch delete mode 100644 patches/server/0988-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch delete mode 100644 patches/server/0989-Fix-entity-type-tags-suggestions-in-selectors.patch create mode 100644 patches/server/0989-Handle-Oversized-block-entities-in-chunks.patch create mode 100644 patches/server/0990-Check-distance-in-entity-interactions.patch delete mode 100644 patches/server/0990-Handle-Oversized-block-entities-in-chunks.patch delete mode 100644 patches/server/0991-Check-distance-in-entity-interactions.patch create mode 100644 patches/server/0991-Configurable-Sand-Duping.patch delete mode 100644 patches/server/0992-Configurable-Sand-Duping.patch create mode 100644 patches/server/0992-Properly-resend-entities.patch delete mode 100644 patches/server/0993-Properly-resend-entities.patch create mode 100644 patches/server/0993-Registry-Modification-API.patch create mode 100644 patches/server/0994-Add-registry-entry-and-builders.patch delete mode 100644 patches/server/0994-Registry-Modification-API.patch delete mode 100644 patches/server/0995-Add-registry-entry-and-builders.patch create mode 100644 patches/server/0995-Proxy-ItemStack-to-CraftItemStack.patch create mode 100644 patches/server/0996-Make-a-PDC-view-accessible-directly-from-ItemStack.patch delete mode 100644 patches/server/0996-Proxy-ItemStack-to-CraftItemStack.patch delete mode 100644 patches/server/0997-Make-a-PDC-view-accessible-directly-from-ItemStack.patch create mode 100644 patches/server/0997-Prioritize-Minecraft-commands-in-function-parsing-an.patch delete mode 100644 patches/server/0998-Prioritize-Minecraft-commands-in-function-parsing-an.patch create mode 100644 patches/server/0998-optimize-dirt-and-snow-spreading.patch create mode 100644 patches/server/0999-Fix-NPE-for-Jukebox-setRecord.patch delete mode 100644 patches/server/0999-optimize-dirt-and-snow-spreading.patch delete mode 100644 patches/server/1000-Fix-NPE-for-Jukebox-setRecord.patch create mode 100644 patches/server/1000-fix-horse-inventories.patch create mode 100644 patches/server/1001-Only-call-EntityDamageEvents-before-actuallyHurt.patch delete mode 100644 patches/server/1001-fix-horse-inventories.patch create mode 100644 patches/server/1002-Add-ItemType-getItemRarity.patch delete mode 100644 patches/server/1002-Only-call-EntityDamageEvents-before-actuallyHurt.patch delete mode 100644 patches/server/1003-Add-ItemType-getItemRarity.patch create mode 100644 patches/server/1003-Add-plugin-info-at-startup.patch delete mode 100644 patches/server/1004-Add-plugin-info-at-startup.patch create mode 100644 patches/server/1004-Make-interaction-leniency-distance-configurable.patch create mode 100644 patches/server/1005-Fix-PickupStatus-getting-reset.patch delete mode 100644 patches/server/1005-Make-interaction-leniency-distance-configurable.patch create mode 100644 patches/server/1006-Check-for-block-type-in-SculkSensorBlock-canActivate.patch delete mode 100644 patches/server/1006-Fix-PickupStatus-getting-reset.patch create mode 100644 patches/server/1007-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch delete mode 100644 patches/server/1007-Check-for-block-type-in-SculkSensorBlock-canActivate.patch delete mode 100644 patches/server/1008-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch create mode 100644 patches/server/1008-Configuration-for-horizontal-only-item-merging.patch create mode 100644 patches/server/1009-Add-skipping-world-symlink-scan.patch delete mode 100644 patches/server/1009-Configuration-for-horizontal-only-item-merging.patch create mode 100644 patches/server/1010-Add-even-more-Enchantment-API.patch delete mode 100644 patches/server/1010-Add-skipping-world-symlink-scan.patch delete mode 100644 patches/server/1011-Add-even-more-Enchantment-API.patch create mode 100644 patches/server/1011-Leashable-API.patch create mode 100644 patches/server/1012-Fix-CraftBukkit-drag-system.patch delete mode 100644 patches/server/1012-Leashable-API.patch delete mode 100644 patches/server/1013-Fix-CraftBukkit-drag-system.patch create mode 100644 patches/server/1013-Fix-SculkBloomEvent-firing-for-block-entity-loading.patch delete mode 100644 patches/server/1014-Fix-SculkBloomEvent-firing-for-block-entity-loading.patch create mode 100644 patches/server/1014-Remove-set-damage-lootable-item-function-from-compas.patch create mode 100644 patches/server/1015-Add-enchantment-seed-update-API.patch delete mode 100644 patches/server/1015-Remove-set-damage-lootable-item-function-from-compas.patch delete mode 100644 patches/server/1016-Add-enchantment-seed-update-API.patch create mode 100644 patches/server/1016-Fix-synchronise-sending-chat-to-client-with-updating.patch create mode 100644 patches/server/1017-Fix-InventoryOpenEvent-cancellation.patch delete mode 100644 patches/server/1017-Fix-synchronise-sending-chat-to-client-with-updating.patch create mode 100644 patches/server/1018-Fire-BlockExpEvent-on-grindstone-use.patch delete mode 100644 patches/server/1018-Fix-InventoryOpenEvent-cancellation.patch create mode 100644 patches/server/1019-Check-dead-flag-in-isAlive.patch delete mode 100644 patches/server/1019-Fire-BlockExpEvent-on-grindstone-use.patch create mode 100644 patches/server/1020-Add-FeatureFlag-API.patch delete mode 100644 patches/server/1020-Check-dead-flag-in-isAlive.patch delete mode 100644 patches/server/1021-Add-FeatureFlag-API.patch create mode 100644 patches/server/1021-Tag-Lifecycle-Events.patch create mode 100644 patches/server/1022-Item-serialization-as-json.patch delete mode 100644 patches/server/1022-Tag-Lifecycle-Events.patch delete mode 100644 patches/server/1023-Item-serialization-as-json.patch create mode 100644 patches/server/1023-Validate-slot-in-PlayerInventory-setSlot.patch create mode 100644 patches/server/1024-Remove-wall-time-unused-skip-tick-protection.patch delete mode 100644 patches/server/1024-Validate-slot-in-PlayerInventory-setSlot.patch create mode 100644 patches/server/1025-Disable-pretty-printing-for-advancement-saving.patch delete mode 100644 patches/server/1025-Remove-wall-time-unused-skip-tick-protection.patch delete mode 100644 patches/server/1026-Disable-pretty-printing-for-advancement-saving.patch create mode 100644 patches/server/1026-Fix-PlayerCommandPreprocessEvent-on-signed-commands.patch create mode 100644 patches/server/1027-Add-enchantWithLevels-with-enchantment-registry-set.patch delete mode 100644 patches/server/1027-Fix-PlayerCommandPreprocessEvent-on-signed-commands.patch delete mode 100644 patches/server/1028-Add-enchantWithLevels-with-enchantment-registry-set.patch create mode 100644 patches/server/1028-Improve-entity-effect-API.patch create mode 100644 patches/server/1029-Add-recipeBrewTime.patch delete mode 100644 patches/server/1029-Improve-entity-effect-API.patch delete mode 100644 patches/server/1030-Add-recipeBrewTime.patch create mode 100644 patches/server/1030-Call-bucket-events-for-cauldrons.patch create mode 100644 patches/server/1031-Add-PlayerInsertLecternBookEvent.patch delete mode 100644 patches/server/1031-Call-bucket-events-for-cauldrons.patch delete mode 100644 patches/server/1032-Add-PlayerInsertLecternBookEvent.patch create mode 100644 patches/server/1032-Void-damage-configuration-API.patch create mode 100644 patches/server/1033-Add-Offline-PDC-API.patch delete mode 100644 patches/server/1033-Void-damage-configuration-API.patch create mode 100644 patches/server/1034-Add-AnvilView-bypassEnchantmentLevelRestriction.patch delete mode 100644 patches/server/1034-Add-Offline-PDC-API.patch delete mode 100644 patches/server/1035-Add-AnvilView-bypassEnchantmentLevelRestriction.patch create mode 100644 patches/server/1035-Add-proper-async-player-disconnections.patch delete mode 100644 patches/server/1036-Add-proper-async-player-disconnections.patch create mode 100644 patches/server/1036-Always-send-Banner-patterns-to-the-client.patch delete mode 100644 patches/server/1037-Always-send-Banner-patterns-to-the-client.patch create mode 100644 patches/server/1037-Rewrite-dataconverter-system.patch create mode 100644 patches/server/1038-Moonrise-optimisation-patches.patch delete mode 100644 patches/server/1038-Rewrite-dataconverter-system.patch create mode 100644 patches/server/1039-API-for-checking-sent-chunks.patch delete mode 100644 patches/server/1039-Moonrise-optimisation-patches.patch delete mode 100644 patches/server/1040-API-for-checking-sent-chunks.patch create mode 100644 patches/server/1040-Fix-CraftWorld-isChunkGenerated.patch create mode 100644 patches/server/1041-Add-startup-flag-to-disable-gamerule-limits.patch delete mode 100644 patches/server/1041-Fix-CraftWorld-isChunkGenerated.patch delete mode 100644 patches/server/1042-Add-startup-flag-to-disable-gamerule-limits.patch create mode 100644 patches/server/1042-Improved-Watchdog-Support.patch create mode 100644 patches/server/1043-Detail-more-information-in-watchdog-dumps.patch delete mode 100644 patches/server/1043-Improved-Watchdog-Support.patch delete mode 100644 patches/server/1044-Detail-more-information-in-watchdog-dumps.patch create mode 100644 patches/server/1044-Entity-load-save-limit-per-chunk.patch create mode 100644 patches/server/1045-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch delete mode 100644 patches/server/1045-Entity-load-save-limit-per-chunk.patch delete mode 100644 patches/server/1046-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch create mode 100644 patches/server/1046-Bundle-spark.patch delete mode 100644 patches/server/1047-Bundle-spark.patch create mode 100644 patches/server/1047-Improve-performance-of-mass-crafts.patch delete mode 100644 patches/server/1048-Improve-performance-of-mass-crafts.patch create mode 100644 patches/server/1048-Incremental-chunk-and-player-saving.patch delete mode 100644 patches/server/1049-Incremental-chunk-and-player-saving.patch create mode 100644 patches/server/1049-Optimise-general-POI-access.patch create mode 100644 patches/server/1050-Fix-entity-tracker-desync-when-new-players-are-added.patch delete mode 100644 patches/server/1050-Optimise-general-POI-access.patch delete mode 100644 patches/server/1051-Fix-entity-tracker-desync-when-new-players-are-added.patch create mode 100644 patches/server/1051-Lag-compensation-ticks.patch delete mode 100644 patches/server/1052-Lag-compensation-ticks.patch create mode 100644 patches/server/1052-Optimise-collision-checking-in-player-move-packet-ha.patch delete mode 100644 patches/server/1053-Optimise-collision-checking-in-player-move-packet-ha.patch create mode 100644 patches/server/1053-Optional-per-player-mob-spawns.patch create mode 100644 patches/server/1054-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch delete mode 100644 patches/server/1054-Optional-per-player-mob-spawns.patch delete mode 100644 patches/server/1055-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch diff --git a/patches/api/0011-Timings-v2.patch b/patches/api/0011-Timings-v2.patch index 36aae54822..a484a8afd2 100644 --- a/patches/api/0011-Timings-v2.patch +++ b/patches/api/0011-Timings-v2.patch @@ -8,7 +8,7 @@ expose isRunning diff --git a/src/main/java/co/aikar/timings/FullServerTickHandler.java b/src/main/java/co/aikar/timings/FullServerTickHandler.java new file mode 100644 -index 0000000000000000000000000000000000000000..3e747abde6fefae90f1c15cb00158bc5303cbe50 +index 0000000000000000000000000000000000000000..73b125979e2f2dfd13cbf689a90b29cc68a36e09 --- /dev/null +++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java @@ -0,0 +1,89 @@ @@ -94,7 +94,7 @@ index 0000000000000000000000000000000000000000..3e747abde6fefae90f1c15cb00158bc5 + TimingsManager.HISTORY.add(new TimingHistory()); + TimingsManager.resetTimings(); + } -+ Bukkit.getUnsafe().reportTimings(); ++ //Bukkit.getUnsafe().reportTimings(); + } + + boolean isViolated() { @@ -1275,10 +1275,10 @@ index 0000000000000000000000000000000000000000..df142a89b8c43acb81eb383eac0ef048 +} diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java new file mode 100644 -index 0000000000000000000000000000000000000000..e81d0bc309de877ed2b5da6122f55c162e9b5f10 +index 0000000000000000000000000000000000000000..95b7cdf0677ef71e6885fa78aa5c75bb500f5f53 --- /dev/null +++ b/src/main/java/co/aikar/timings/Timings.java -@@ -0,0 +1,331 @@ +@@ -0,0 +1,325 @@ +/* + * This file is licensed under the MIT License (MIT). + * @@ -1426,14 +1426,8 @@ index 0000000000000000000000000000000000000000..e81d0bc309de877ed2b5da6122f55c16 + * @param enabled Should timings be reported + */ + public static void setTimingsEnabled(boolean enabled) { -+ timingsEnabled = enabled; -+ warnAboutDeprecationOnEnable(); -+ reset(); -+ } -+ -+ private static void warnAboutDeprecationOnEnable() { -+ if (timingsEnabled && !warnedAboutDeprecationOnEnable) { -+ Bukkit.getLogger().warning(PlainTextComponentSerializer.plainText().serialize(deprecationMessage())); ++ if (enabled && !warnedAboutDeprecationOnEnable) { ++ Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage())); + warnedAboutDeprecationOnEnable = true; + } + } @@ -1441,7 +1435,7 @@ index 0000000000000000000000000000000000000000..e81d0bc309de877ed2b5da6122f55c16 + public static Component deprecationMessage() { + return Component.text() + .color(TextColor.color(0xffc93a)) -+ .append(Component.text("[!] The timings profiler has been enabled but has been scheduled for removal from Paper in the future.")) ++ .append(Component.text("[!] The timings profiler is in no-op mode and will be fully removed in a later update.")) + .append(Component.newline()) + .append(Component.text(" We recommend migrating to the spark profiler.")) + .append(Component.newline()) @@ -1612,10 +1606,10 @@ index 0000000000000000000000000000000000000000..e81d0bc309de877ed2b5da6122f55c16 + diff --git a/src/main/java/co/aikar/timings/TimingsCommand.java b/src/main/java/co/aikar/timings/TimingsCommand.java new file mode 100644 -index 0000000000000000000000000000000000000000..95d87c9dbf2b237787294dfbe7fed87a36e6dedf +index 0000000000000000000000000000000000000000..b83e5ff7ada8771fdf27ba9807c77ba6a4ce12da --- /dev/null +++ b/src/main/java/co/aikar/timings/TimingsCommand.java -@@ -0,0 +1,126 @@ +@@ -0,0 +1,127 @@ +/* + * This file is licensed under the MIT License (MIT). + * @@ -1674,8 +1668,9 @@ index 0000000000000000000000000000000000000000..95d87c9dbf2b237787294dfbe7fed87a + if (!testPermission(sender)) { + return true; + } -+ if (false) { ++ if (true) { + sender.sendMessage(Timings.deprecationMessage()); ++ return true; + } + if (args.length < 1) { + sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED)); @@ -2906,35 +2901,6 @@ index fa6ad07214d5e38866bf6bee9139c6c938e9f51a..57c9b560c77a56588870598acb543469 /** * Sends the component to the player * -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index d8b346fe0f9634218954fe818d53272a0896af9c..12ef99f1c91b92a133611c5f5aeaaeebd02ce232 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -40,6 +40,11 @@ public interface UnsafeValues { - net.kyori.adventure.text.Component resolveWithContext(net.kyori.adventure.text.Component component, org.bukkit.command.CommandSender context, org.bukkit.entity.Entity scoreboardSubject, boolean bypassPermissions) throws java.io.IOException; - // Paper end - -+ /** -+ * @deprecated Timings will be removed in the future -+ */ -+ @Deprecated(forRemoval = true) -+ void reportTimings(); // Paper - Material toLegacy(Material material); - - Material fromLegacy(Material material); -@@ -151,4 +156,12 @@ public interface UnsafeValues { - return !Bukkit.getUnsafe().isSupportedApiVersion(plugin.getDescription().getAPIVersion()); - } - // Paper end -+ -+ // Paper start -+ /** -+ * @deprecated Timings will be removed in the future -+ */ -+ @Deprecated(forRemoval = true) -+ String getTimingsServerName(); -+ // Paper end - } diff --git a/src/main/java/org/bukkit/command/BufferedCommandSender.java b/src/main/java/org/bukkit/command/BufferedCommandSender.java new file mode 100644 index 0000000000000000000000000000000000000000..45ed63797b13e114bf3795c80a6c3967d8eb2351 @@ -3508,7 +3474,7 @@ index 84befa1e5123038b80e0734622a5174634f5a982..22de066aef71ad2cf135d5b6f5d6f224 @NotNull diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 46c7be5fa69f13900860b9944523beea16f2409b..6018574cd15b802833613beefa88da15dc2730cb 100644 +index 46c7be5fa69f13900860b9944523beea16f2409b..f97669c8b58bc287fc289eeb098836ae314b053a 100644 --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java @@ -381,7 +381,6 @@ public final class SimplePluginManager implements PluginManager { @@ -3559,9 +3525,11 @@ index 46c7be5fa69f13900860b9944523beea16f2409b..6018574cd15b802833613beefa88da15 } /** -@@ -933,7 +933,7 @@ public final class SimplePluginManager implements PluginManager { +@@ -932,8 +932,9 @@ public final class SimplePluginManager implements PluginManager { + * * @param use True if per event timing code should be used */ ++ @Deprecated(forRemoval = true) public void useTimings(boolean use) { - useTimings = use; + co.aikar.timings.Timings.setTimingsEnabled(use); // Paper diff --git a/patches/api/0012-Add-command-line-option-to-load-extra-plugin-jars-no.patch b/patches/api/0012-Add-command-line-option-to-load-extra-plugin-jars-no.patch index c73bf65b97..1faeb90190 100644 --- a/patches/api/0012-Add-command-line-option-to-load-extra-plugin-jars-no.patch +++ b/patches/api/0012-Add-command-line-option-to-load-extra-plugin-jars-no.patch @@ -55,7 +55,7 @@ index 57c9b560c77a56588870598acb543469040ceec1..8949b8e29ae7f412481291630a5cb7b5 * Used for all administrative messages, such as an operator using a * command. diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 6018574cd15b802833613beefa88da15dc2730cb..e7b1895d3918487d711afcbe41d76863d85c0a62 100644 +index f97669c8b58bc287fc289eeb098836ae314b053a..2c77b6ab388bd689acb8d84ec62bd5df1eb9373e 100644 --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java @@ -117,9 +117,22 @@ public final class SimplePluginManager implements PluginManager { diff --git a/patches/api/0015-Expose-server-build-information.patch b/patches/api/0015-Expose-server-build-information.patch index f1bf77caf8..2853b45626 100644 --- a/patches/api/0015-Expose-server-build-information.patch +++ b/patches/api/0015-Expose-server-build-information.patch @@ -316,21 +316,22 @@ index ba28d9f3213ca4b5f15178dc637bff37a8896edc..8a07f21eeb04fb54032ce377a1478f60 * Gets a view of all currently logged in players. This {@linkplain * Collections#unmodifiableCollection(Collection) view} is a reused diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 12ef99f1c91b92a133611c5f5aeaaeebd02ce232..6e67fdb091a006d2d13bc2d93db4d55348af4c8f 100644 +index d8b346fe0f9634218954fe818d53272a0896af9c..45ed0007d6de20b98794b3ccaef57aed213e72d4 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -163,5 +163,12 @@ public interface UnsafeValues { - */ - @Deprecated(forRemoval = true) - String getTimingsServerName(); +@@ -151,4 +151,13 @@ public interface UnsafeValues { + return !Bukkit.getUnsafe().isSupportedApiVersion(plugin.getDescription().getAPIVersion()); + } + // Paper end + ++ // Paper start + /** + * Called once by the version command on first use, then cached. + */ + default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { + return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher(); + } - // Paper end ++ // Paper end } diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java index 263208d3cba36cb80c9ee4e3022ef702ea113df2..e64bb57f74e6d6f78927be228825b3e0bdf41f48 100644 diff --git a/patches/api/0021-Add-exception-reporting-event.patch b/patches/api/0021-Add-exception-reporting-event.patch index adf50a8c29..c592c2b2ee 100644 --- a/patches/api/0021-Add-exception-reporting-event.patch +++ b/patches/api/0021-Add-exception-reporting-event.patch @@ -494,7 +494,7 @@ index 36fc2c35395c72f8b81a2a2f3265fd205384ce26..c7fa1d235cea78bda4656ed66b8d42b1 } diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index e7b1895d3918487d711afcbe41d76863d85c0a62..003bece642b682985625db93cad93026352bfc66 100644 +index 2c77b6ab388bd689acb8d84ec62bd5df1eb9373e..b878e7167cfcdea0e224c182b40abeadd339d3b3 100644 --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java @@ -528,7 +528,8 @@ public final class SimplePluginManager implements PluginManager { diff --git a/patches/api/0182-Add-Raw-Byte-ItemStack-Serialization.patch b/patches/api/0182-Add-Raw-Byte-ItemStack-Serialization.patch index bfdff2a3f4..b852c64ded 100644 --- a/patches/api/0182-Add-Raw-Byte-ItemStack-Serialization.patch +++ b/patches/api/0182-Add-Raw-Byte-ItemStack-Serialization.patch @@ -8,10 +8,10 @@ Serializes using NBT which is safer for server data migrations than bukkits form Co-authored-by: Nassim Jahnke diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 6e67fdb091a006d2d13bc2d93db4d55348af4c8f..e41d5d9b810c8816cd0d1eba5fd1ea56252fb0df 100644 +index 45ed0007d6de20b98794b3ccaef57aed213e72d4..dd81e309c584e37e4bc7644261ecc649e1237570 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -170,5 +170,9 @@ public interface UnsafeValues { +@@ -159,5 +159,9 @@ public interface UnsafeValues { default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher(); } diff --git a/patches/api/0205-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch b/patches/api/0205-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch index c5e6d200ab..241d581e0c 100644 --- a/patches/api/0205-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch +++ b/patches/api/0205-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Expose the Entity Counter to allow plugins to use valid and diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index e41d5d9b810c8816cd0d1eba5fd1ea56252fb0df..64be4e60a03cb7cdc21013837d241d288695b69d 100644 +index dd81e309c584e37e4bc7644261ecc649e1237570..db48f30704efa6928599a5cebf5ce577c8430198 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -174,5 +174,12 @@ public interface UnsafeValues { +@@ -163,5 +163,12 @@ public interface UnsafeValues { byte[] serializeItem(ItemStack item); ItemStack deserializeItem(byte[] data); diff --git a/patches/api/0253-Expand-world-key-API.patch b/patches/api/0253-Expand-world-key-API.patch index 2436c924af..2716158a70 100644 --- a/patches/api/0253-Expand-world-key-API.patch +++ b/patches/api/0253-Expand-world-key-API.patch @@ -100,10 +100,10 @@ index 943f8881ea23481ea5d5125b6ec7c9c6f763f0b0..42930006b6425b5d82233e4ffe7025ce * Create a new virtual {@link WorldBorder}. *

diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 64be4e60a03cb7cdc21013837d241d288695b69d..0231b79d96d535e0ae37296b3e806844740783ca 100644 +index db48f30704efa6928599a5cebf5ce577c8430198..4229db3c6abb693803a4bdd5a71e426c688f26cc 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -181,5 +181,10 @@ public interface UnsafeValues { +@@ -170,5 +170,10 @@ public interface UnsafeValues { * Use this when sending custom packets, so that there are no collisions on the client or server. */ public int nextEntityId(); diff --git a/patches/api/0255-Expose-protocol-version.patch b/patches/api/0255-Expose-protocol-version.patch index 9ba0c40a96..f6cace865e 100644 --- a/patches/api/0255-Expose-protocol-version.patch +++ b/patches/api/0255-Expose-protocol-version.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Expose protocol version diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 0231b79d96d535e0ae37296b3e806844740783ca..51473ffbec65a2344449daa8ff5cf535b0b60520 100644 +index 4229db3c6abb693803a4bdd5a71e426c688f26cc..f33426207c403906c3c6fb99e848fd7ecbffd127 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -186,5 +186,12 @@ public interface UnsafeValues { +@@ -175,5 +175,12 @@ public interface UnsafeValues { * Just don't use it. */ @org.jetbrains.annotations.NotNull String getMainLevelName(); diff --git a/patches/api/0272-ItemStack-repair-check-API.patch b/patches/api/0272-ItemStack-repair-check-API.patch index 6ef26350c7..6385fdeb47 100644 --- a/patches/api/0272-ItemStack-repair-check-API.patch +++ b/patches/api/0272-ItemStack-repair-check-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] ItemStack repair check API diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 51473ffbec65a2344449daa8ff5cf535b0b60520..07669aad6d9910174fbc8fdf3cdd54211fbfcee3 100644 +index f33426207c403906c3c6fb99e848fd7ecbffd127..3ef6ffb506a7fdd05a08353f342e45de8066ca19 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -193,5 +193,15 @@ public interface UnsafeValues { +@@ -182,5 +182,15 @@ public interface UnsafeValues { * @return the server's protocol version */ int getProtocolVersion(); diff --git a/patches/api/0304-Get-entity-default-attributes.patch b/patches/api/0304-Get-entity-default-attributes.patch index fd13ed8d7c..deca580fd3 100644 --- a/patches/api/0304-Get-entity-default-attributes.patch +++ b/patches/api/0304-Get-entity-default-attributes.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Get entity default attributes diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 07669aad6d9910174fbc8fdf3cdd54211fbfcee3..a25f7378e5cef3899c38dd34d369da0441951f24 100644 +index 3ef6ffb506a7fdd05a08353f342e45de8066ca19..b8627d845bbc8c845af364408d3b6abb57c7308b 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -203,5 +203,22 @@ public interface UnsafeValues { +@@ -192,5 +192,22 @@ public interface UnsafeValues { * @return true if valid repair, false if not */ public boolean isValidRepairItemStack(@org.jetbrains.annotations.NotNull ItemStack itemToBeRepaired, @org.jetbrains.annotations.NotNull ItemStack repairMaterial); diff --git a/patches/api/0312-Add-Raw-Byte-Entity-Serialization.patch b/patches/api/0312-Add-Raw-Byte-Entity-Serialization.patch index 790704d4e9..abe5d9f163 100644 --- a/patches/api/0312-Add-Raw-Byte-Entity-Serialization.patch +++ b/patches/api/0312-Add-Raw-Byte-Entity-Serialization.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add Raw Byte Entity Serialization diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index a25f7378e5cef3899c38dd34d369da0441951f24..3aeac7b102f7c6e6186d168294ea73ff022f9349 100644 +index b8627d845bbc8c845af364408d3b6abb57c7308b..ef22077e2bf9709bef21e259cfa6435f80305b5e 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -175,6 +175,14 @@ public interface UnsafeValues { +@@ -164,6 +164,14 @@ public interface UnsafeValues { ItemStack deserializeItem(byte[] data); diff --git a/patches/api/0358-Add-NamespacedKey-biome-methods.patch b/patches/api/0358-Add-NamespacedKey-biome-methods.patch index adc8f6a1e2..be2c0e7b2a 100644 --- a/patches/api/0358-Add-NamespacedKey-biome-methods.patch +++ b/patches/api/0358-Add-NamespacedKey-biome-methods.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Add NamespacedKey biome methods Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 3aeac7b102f7c6e6186d168294ea73ff022f9349..4f3e6e2698b28922e7b6448eddd5b166f4631759 100644 +index ef22077e2bf9709bef21e259cfa6435f80305b5e..14cf57a96f47ba666f05cedbc0005ff0fec6a33d 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -229,4 +229,33 @@ public interface UnsafeValues { +@@ -218,4 +218,33 @@ public interface UnsafeValues { */ @org.jetbrains.annotations.NotNull org.bukkit.attribute.Attributable getDefaultEntityAttributes(@org.jetbrains.annotations.NotNull NamespacedKey entityKey); // Paper end diff --git a/patches/api/0402-Fix-custom-statistic-criteria-creation.patch b/patches/api/0402-Fix-custom-statistic-criteria-creation.patch index 5e3f26f4f3..ff4bad9d35 100644 --- a/patches/api/0402-Fix-custom-statistic-criteria-creation.patch +++ b/patches/api/0402-Fix-custom-statistic-criteria-creation.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix custom statistic criteria creation diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 4f3e6e2698b28922e7b6448eddd5b166f4631759..334e392800803816cf502c2920c4a85774d6b0b2 100644 +index 14cf57a96f47ba666f05cedbc0005ff0fec6a33d..57b51acd566f6ccabeea0b3f4c76b19547d35b5a 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -258,4 +258,6 @@ public interface UnsafeValues { +@@ -247,4 +247,6 @@ public interface UnsafeValues { */ void setBiomeKey(RegionAccessor accessor, int x, int y, int z, NamespacedKey biomeKey); // Paper end - namespaced key biome methods diff --git a/patches/api/0440-Add-api-for-spawn-egg-texture-colors.patch b/patches/api/0440-Add-api-for-spawn-egg-texture-colors.patch index 996340cf25..14a80bca1c 100644 --- a/patches/api/0440-Add-api-for-spawn-egg-texture-colors.patch +++ b/patches/api/0440-Add-api-for-spawn-egg-texture-colors.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add api for spawn egg texture colors diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 334e392800803816cf502c2920c4a85774d6b0b2..27ac8e80192924eb38e5ceaee575ac418e92b410 100644 +index 57b51acd566f6ccabeea0b3f4c76b19547d35b5a..38e84d98670b45b1f855885cf07ce13f0433fa49 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -260,4 +260,17 @@ public interface UnsafeValues { +@@ -249,4 +249,17 @@ public interface UnsafeValues { // Paper end - namespaced key biome methods String getStatisticCriteriaKey(@NotNull org.bukkit.Statistic statistic); // Paper - fix custom stats criteria creation diff --git a/patches/api/0441-Add-Lifecycle-Event-system.patch b/patches/api/0441-Add-Lifecycle-Event-system.patch index 31bfe9a70f..2d2d639018 100644 --- a/patches/api/0441-Add-Lifecycle-Event-system.patch +++ b/patches/api/0441-Add-Lifecycle-Event-system.patch @@ -546,10 +546,10 @@ index 0000000000000000000000000000000000000000..f70814de0d6c40b2c1c9921b8abdd116 + } +} diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 27ac8e80192924eb38e5ceaee575ac418e92b410..141d5a964cc299284aecd4d34d57008a32f94247 100644 +index 38e84d98670b45b1f855885cf07ce13f0433fa49..81b1c024e27a7021982336b94fc1e1ba33308f6c 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -273,4 +273,12 @@ public interface UnsafeValues { +@@ -262,4 +262,12 @@ public interface UnsafeValues { */ @Nullable org.bukkit.Color getSpawnEggLayerColor(org.bukkit.entity.EntityType entityType, int layer); // Paper end - spawn egg color visibility diff --git a/patches/api/0442-ItemStack-Tooltip-API.patch b/patches/api/0442-ItemStack-Tooltip-API.patch index 4af91c3ade..1d0644e6e1 100644 --- a/patches/api/0442-ItemStack-Tooltip-API.patch +++ b/patches/api/0442-ItemStack-Tooltip-API.patch @@ -110,10 +110,10 @@ index 0000000000000000000000000000000000000000..a649b90dfac6000c01579a48234a1138 + } +} diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 141d5a964cc299284aecd4d34d57008a32f94247..31217b38e769f97801fa1afefeb223d1c755cabd 100644 +index 81b1c024e27a7021982336b94fc1e1ba33308f6c..e5144471056e69586c1693a9264a3995387de3cc 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -281,4 +281,6 @@ public interface UnsafeValues { +@@ -270,4 +270,6 @@ public interface UnsafeValues { @org.jetbrains.annotations.ApiStatus.Internal io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck); // Paper end - lifecycle event API diff --git a/patches/api/0472-Registry-Modification-API.patch b/patches/api/0472-Registry-Modification-API.patch index 6eca654483..b51badfa70 100644 --- a/patches/api/0472-Registry-Modification-API.patch +++ b/patches/api/0472-Registry-Modification-API.patch @@ -900,10 +900,10 @@ index 67cf3fcad21a8977d6fad172cc776b628ab68f25..b4ef3133fdd9d79a3381cf8f659ff561 } } diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 31217b38e769f97801fa1afefeb223d1c755cabd..9bdba60fa96edbc4be5dcf54a815579db887048b 100644 +index e5144471056e69586c1693a9264a3995387de3cc..2c365ecf3f5a5252e489bc1dc04359e766a2d739 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -283,4 +283,6 @@ public interface UnsafeValues { +@@ -272,4 +272,6 @@ public interface UnsafeValues { // Paper end - lifecycle event API @NotNull java.util.List computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines diff --git a/patches/api/0474-Proxy-ItemStack-to-CraftItemStack.patch b/patches/api/0474-Proxy-ItemStack-to-CraftItemStack.patch index 246fa425d8..157b63eeb4 100644 --- a/patches/api/0474-Proxy-ItemStack-to-CraftItemStack.patch +++ b/patches/api/0474-Proxy-ItemStack-to-CraftItemStack.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Proxy ItemStack to CraftItemStack diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 9bdba60fa96edbc4be5dcf54a815579db887048b..330e3013eda204aa9b33d5e1c3104e0b595abdbc 100644 +index 2c365ecf3f5a5252e489bc1dc04359e766a2d739..06b7af5dbae3dd1c5cb024cc875162725a0b8c37 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -285,4 +285,6 @@ public interface UnsafeValues { +@@ -274,4 +274,6 @@ public interface UnsafeValues { @NotNull java.util.List computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines io.papermc.paper.registry.tag.@Nullable Tag getTag(io.papermc.paper.registry.tag.@NotNull TagKey tagKey); // Paper - hack to get tags for non-server backed registries diff --git a/patches/api/0485-Add-FeatureFlag-API.patch b/patches/api/0485-Add-FeatureFlag-API.patch index 9afc644014..26442d7b01 100644 --- a/patches/api/0485-Add-FeatureFlag-API.patch +++ b/patches/api/0485-Add-FeatureFlag-API.patch @@ -247,10 +247,10 @@ index eb33e8e671972aa308ad75a7ce9aa9ac526f470f..05ecf3cb38ff42c8b52405d900197e6b /** * Gets the {@link Biome} at the given {@link Location}. diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 330e3013eda204aa9b33d5e1c3104e0b595abdbc..c80e0ef587a001ee6de3f5c182cc9696d58bafeb 100644 +index 06b7af5dbae3dd1c5cb024cc875162725a0b8c37..aa3916b0d8e40615a7ae142e254277744b4f024e 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -114,8 +114,7 @@ public interface UnsafeValues { +@@ -109,8 +109,7 @@ public interface UnsafeValues { String getTranslationKey(Attribute attribute); diff --git a/patches/api/0487-Item-serialization-as-json.patch b/patches/api/0487-Item-serialization-as-json.patch index d2951870a1..c2b00d8d3d 100644 --- a/patches/api/0487-Item-serialization-as-json.patch +++ b/patches/api/0487-Item-serialization-as-json.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Item serialization as json diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index c80e0ef587a001ee6de3f5c182cc9696d58bafeb..10c87b7c19ed3eab28fdce5f225df3767292ee0a 100644 +index aa3916b0d8e40615a7ae142e254277744b4f024e..e4084369d12390bb5c92ab58ad34ff07afea1142 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -174,6 +174,36 @@ public interface UnsafeValues { +@@ -163,6 +163,36 @@ public interface UnsafeValues { ItemStack deserializeItem(byte[] data); diff --git a/patches/server/0005-Paper-config-files.patch b/patches/server/0005-Paper-config-files.patch index 3303f32c8a..c4181a6029 100644 --- a/patches/server/0005-Paper-config-files.patch +++ b/patches/server/0005-Paper-config-files.patch @@ -487,13 +487,12 @@ index 0000000000000000000000000000000000000000..d9502ba028a96f9cc846f9ed428bd806 +} diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java new file mode 100644 -index 0000000000000000000000000000000000000000..7e88b1fc1ff700a7771b38f139f4472eaeaf8714 +index 0000000000000000000000000000000000000000..f0d470d7770e119f734b9e72021c806d0ea8ecbd --- /dev/null +++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -0,0 +1,355 @@ +@@ -0,0 +1,330 @@ +package io.papermc.paper.configuration; + -+import co.aikar.timings.MinecraftTimings; +import com.mojang.logging.LogUtils; +import io.papermc.paper.configuration.constraint.Constraints; +import io.papermc.paper.configuration.type.number.DoubleOr; @@ -510,7 +509,6 @@ index 0000000000000000000000000000000000000000..7e88b1fc1ff700a7771b38f139f4472e +import org.spongepowered.configurate.objectmapping.meta.Required; +import org.spongepowered.configurate.objectmapping.meta.Setting; + -+import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; @@ -592,29 +590,6 @@ index 0000000000000000000000000000000000000000..7e88b1fc1ff700a7771b38f139f4472e + public boolean enableImmediately = false; + } + -+ @Deprecated(forRemoval = true) -+ public Timings timings; -+ -+ @Deprecated(forRemoval = true) -+ public class Timings extends ConfigurationPart { -+ public boolean enabled = false; -+ public boolean verbose = true; -+ public String url = "https://timings.aikar.co/"; -+ public boolean serverNamePrivacy = false; -+ public List hiddenConfigEntries = List.of( -+ "database", -+ "proxies.velocity.secret" -+ ); -+ public int historyInterval = 300; -+ public int historyLength = 3600; -+ public String serverName = "Unknown Server"; -+ -+ @PostProcess -+ private void postProcess() { -+ MinecraftTimings.processConfig(this); -+ } -+ } -+ + public Proxies proxies; + + public class Proxies extends ConfigurationPart { diff --git a/patches/server/0009-MC-Utils.patch b/patches/server/0009-MC-Utils.patch index b7549f7365..c7768b91e2 100644 --- a/patches/server/0009-MC-Utils.patch +++ b/patches/server/0009-MC-Utils.patch @@ -4542,10 +4542,10 @@ index 46cab7a8c7b87ab01b26074b04f5a02b3907cfc4..49019b4a9bc4e634d54a9b0acaf9229a + // Paper end } diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index 7e88b1fc1ff700a7771b38f139f4472eaeaf8714..904d2f96a60e72aa089fdfe6be08044b04f995c1 100644 +index f0d470d7770e119f734b9e72021c806d0ea8ecbd..c3fe4481dd35f80815716e48beeeb07b1f51e30b 100644 --- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -242,7 +242,7 @@ public class GlobalConfiguration extends ConfigurationPart { +@@ -217,7 +217,7 @@ public class GlobalConfiguration extends ConfigurationPart { @PostProcess private void postProcess() { diff --git a/patches/server/0023-Further-improve-server-tick-loop.patch b/patches/server/0023-Further-improve-server-tick-loop.patch new file mode 100644 index 0000000000..87be9b027e --- /dev/null +++ b/patches/server/0023-Further-improve-server-tick-loop.patch @@ -0,0 +1,233 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 1 Mar 2016 23:09:29 -0600 +Subject: [PATCH] Further improve server tick loop + +Improves how the catchup buffer is handled, allowing it to roll both ways +increasing the effeciency of the thread sleep so it only will sleep once. + +Also increases the buffer of the catchup to ensure server stays at 20 TPS unless extreme conditions + +Previous implementation did not calculate TPS correctly. +Switch to a realistic rolling average and factor in std deviation as an extra reporting variable + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 3322865949fe5ddaab2dffc39260b75093f0f204..4a573e8b7cd90f65c190982662e92a11f79a1d3e 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -307,7 +307,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); + public int autosavePeriod; + public Commands vanillaCommandDispatcher; +@@ -316,7 +316,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) { ++ sender.sendMessage(net.kyori.adventure.text.Component.text() ++ .append(net.kyori.adventure.text.Component.text("Current Memory Usage: ", net.kyori.adventure.text.format.NamedTextColor.GOLD)) ++ .append(net.kyori.adventure.text.Component.text(((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)", net.kyori.adventure.text.format.NamedTextColor.GREEN)) ++ ); ++ if (!this.hasShownMemoryWarning) { ++ sender.sendMessage(WARN_MSG); ++ this.hasShownMemoryWarning = true; ++ } + } +- sender.sendMessage( sb.substring( 0, sb.length() - 2 ) ); +- sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " +- + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)"); ++ // Paper end + + return true; + } + +- private String format(double tps) ++ private boolean hasShownMemoryWarning; // Paper ++ private static net.kyori.adventure.text.Component format(double tps) // Paper - Made static + { +- return ( ( tps > 18.0 ) ? ChatColor.GREEN : ( tps > 16.0 ) ? ChatColor.YELLOW : ChatColor.RED ).toString() +- + ( ( tps > 20.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 ); ++ // Paper ++ net.kyori.adventure.text.format.TextColor color = ( ( tps > 18.0 ) ? net.kyori.adventure.text.format.NamedTextColor.GREEN : ( tps > 16.0 ) ? net.kyori.adventure.text.format.NamedTextColor.YELLOW : net.kyori.adventure.text.format.NamedTextColor.RED ); ++ String amount = Math.min(Math.round(tps * 100.0) / 100.0, 20.0) + (tps > 21.0 ? "*" : ""); // Paper - only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise ++ return net.kyori.adventure.text.Component.text(amount, color); ++ // Paper end + } + } diff --git a/patches/server/0023-Timings-v2.patch b/patches/server/0023-Timings-v2.patch deleted file mode 100644 index 92fc3f0b70..0000000000 --- a/patches/server/0023-Timings-v2.patch +++ /dev/null @@ -1,2077 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 3 Mar 2016 04:00:11 -0600 -Subject: [PATCH] Timings v2 - - -diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4bd813161a5d76a83cdbd0a9209b9ea9e60ffe1b ---- /dev/null -+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java -@@ -0,0 +1,169 @@ -+package co.aikar.timings; -+ -+import com.google.common.collect.MapMaker; -+import io.papermc.paper.configuration.GlobalConfiguration; -+import net.minecraft.commands.functions.CommandFunction; -+import net.minecraft.network.protocol.Packet; -+import net.minecraft.world.level.block.Block; -+import net.minecraft.world.level.block.entity.BlockEntity; -+import org.bukkit.plugin.Plugin; -+import org.bukkit.scheduler.BukkitTask; -+ -+import org.bukkit.craftbukkit.scheduler.CraftTask; -+ -+import java.util.Map; -+ -+// TODO: Re-implement missing timers -+@Deprecated(forRemoval = true) -+public final class MinecraftTimings { -+ -+ public static final Timing serverOversleep = Timings.ofSafe("Server Oversleep"); -+ public static final Timing playerListTimer = Timings.ofSafe("Player List"); -+ public static final Timing commandFunctionsTimer = Timings.ofSafe("Command Functions"); -+ public static final Timing connectionTimer = Timings.ofSafe("Connection Handler"); -+ public static final Timing tickablesTimer = Timings.ofSafe("Tickables"); -+ public static final Timing minecraftSchedulerTimer = Timings.ofSafe("Minecraft Scheduler"); -+ public static final Timing bukkitSchedulerTimer = Timings.ofSafe("Bukkit Scheduler"); -+ public static final Timing bukkitSchedulerPendingTimer = Timings.ofSafe("Bukkit Scheduler - Pending"); -+ public static final Timing bukkitSchedulerFinishTimer = Timings.ofSafe("Bukkit Scheduler - Finishing"); -+ public static final Timing chunkIOTickTimer = Timings.ofSafe("ChunkIOTick"); -+ public static final Timing timeUpdateTimer = Timings.ofSafe("Time Update"); -+ public static final Timing serverCommandTimer = Timings.ofSafe("Server Command"); -+ public static final Timing savePlayers = Timings.ofSafe("Save Players"); -+ -+ public static final Timing tickEntityTimer = Timings.ofSafe("## tickEntity"); -+ public static final Timing tickTileEntityTimer = Timings.ofSafe("## tickTileEntity"); -+ public static final Timing packetProcessTimer = Timings.ofSafe("## Packet Processing"); -+ public static final Timing scheduledBlocksTimer = Timings.ofSafe("## Scheduled Blocks"); -+ public static final Timing structureGenerationTimer = Timings.ofSafe("Structure Generation"); -+ -+ public static final Timing processQueueTimer = Timings.ofSafe("processQueue"); -+ public static final Timing processTasksTimer = Timings.ofSafe("processTasks"); -+ -+ public static final Timing playerCommandTimer = Timings.ofSafe("playerCommand"); -+ -+ public static final Timing entityActivationCheckTimer = Timings.ofSafe("entityActivationCheck"); -+ -+ public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update"); -+ public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate"); -+ -+ private static final Map, String> taskNameCache = new MapMaker().weakKeys().makeMap(); -+ -+ private MinecraftTimings() {} -+ -+ public static Timing getInternalTaskName(String taskName) { -+ return Timings.ofSafe(taskName); -+ } -+ -+ /** -+ * Gets a timer associated with a plugins tasks. -+ * @param bukkitTask -+ * @param period -+ * @return -+ */ -+ public static Timing getPluginTaskTimings(BukkitTask bukkitTask, long period) { -+ if (!bukkitTask.isSync()) { -+ return NullTimingHandler.NULL; -+ } -+ Plugin plugin; -+ -+ CraftTask craftTask = (CraftTask) bukkitTask; -+ -+ final Class taskClass = craftTask.getTaskClass(); -+ if (bukkitTask.getOwner() != null) { -+ plugin = bukkitTask.getOwner(); -+ } else { -+ plugin = TimingsManager.getPluginByClassloader(taskClass); -+ } -+ -+ final String taskname = taskNameCache.computeIfAbsent(taskClass, clazz -> { -+ try { -+ String clsName = !clazz.isMemberClass() -+ ? clazz.getName() -+ : clazz.getCanonicalName(); -+ if (clsName != null && clsName.contains("$Lambda$")) { -+ clsName = clsName.replaceAll("(Lambda\\$.*?)/.*", "$1"); -+ } -+ return clsName != null ? clsName : "UnknownTask"; -+ } catch (Throwable ex) { -+ new Exception("Error occurred detecting class name", ex).printStackTrace(); -+ return "MangledClassFile"; -+ } -+ }); -+ -+ StringBuilder name = new StringBuilder(64); -+ name.append("Task: ").append(taskname); -+ if (period > 0) { -+ name.append(" (interval:").append(period).append(")"); -+ } else { -+ name.append(" (Single)"); -+ } -+ -+ if (plugin == null) { -+ return Timings.ofSafe(null, name.toString()); -+ } -+ -+ return Timings.ofSafe(plugin, name.toString()); -+ } -+ -+ /** -+ * Get a named timer for the specified entity type to track type specific timings. -+ * @param entityType -+ * @return -+ */ -+ public static Timing getEntityTimings(String entityType, String type) { -+ return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType + " - " + type, tickEntityTimer); -+ } -+ -+ /** -+ * Get a named timer for the specified tile entity type to track type specific timings. -+ * @param entity -+ * @return -+ */ -+ public static Timing getTileEntityTimings(BlockEntity entity) { -+ String entityType = entity.getClass().getName(); -+ return Timings.ofSafe("Minecraft", "## tickTileEntity - " + entityType, tickTileEntityTimer); -+ } -+ public static Timing getCancelTasksTimer() { -+ return Timings.ofSafe("Cancel Tasks"); -+ } -+ public static Timing getCancelTasksTimer(Plugin plugin) { -+ return Timings.ofSafe(plugin, "Cancel Tasks"); -+ } -+ -+ public static void stopServer() { -+ TimingsManager.stopServer(); -+ } -+ -+ public static Timing getBlockTiming(Block block) { -+ return Timings.ofSafe("## Scheduled Block: " + block.toString(), scheduledBlocksTimer); -+ } -+/* -+ public static Timing getStructureTiming(StructureGenerator structureGenerator) { -+ return Timings.ofSafe("Structure Generator - " + structureGenerator.getName(), structureGenerationTimer); -+ }*/ -+ -+ public static Timing getPacketTiming(Packet packet) { -+ return Timings.ofSafe("## Packet - " + packet.getClass().getName(), packetProcessTimer); -+ } -+ -+ public static Timing getCommandFunctionTiming(CommandFunction function) { -+ return Timings.ofSafe("Command Function - " + function.id()); -+ } -+ -+ public static void processConfig(GlobalConfiguration.Timings config) { -+ TimingsManager.url = config.url; -+ if (!TimingsManager.url.endsWith("/")) { -+ TimingsManager.url += "/"; -+ } -+ TimingsManager.privacy = config.serverNamePrivacy; -+ if (!config.hiddenConfigEntries.contains("proxies.velocity.secret")) { -+ config.hiddenConfigEntries.add("proxies.velocity.secret"); -+ } -+ TimingsManager.hiddenConfigs.addAll(config.hiddenConfigEntries); -+ co.aikar.timings.Timings.setVerboseTimingsEnabled(config.verbose); -+ co.aikar.timings.Timings.setTimingsEnabled(config.enabled); -+ co.aikar.timings.Timings.setHistoryInterval(config.historyInterval * 20); -+ co.aikar.timings.Timings.setHistoryLength(config.historyLength * 20); -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -new file mode 100644 -index 0000000000000000000000000000000000000000..49028463ba47e760281545c2f7597e3db8d6c453 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -0,0 +1,388 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import com.google.common.collect.Sets; -+import io.papermc.paper.adventure.PaperAdventure; -+import net.kyori.adventure.text.event.ClickEvent; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -+import net.minecraft.server.MinecraftServer; -+import org.apache.commons.lang.StringUtils; -+import org.bukkit.Bukkit; -+import org.bukkit.Material; -+import org.bukkit.configuration.ConfigurationSection; -+import org.bukkit.configuration.MemorySection; -+import org.bukkit.entity.EntityType; -+import org.json.simple.JSONObject; -+import org.json.simple.JSONValue; -+import oshi.SystemInfo; -+import oshi.hardware.HardwareAbstractionLayer; -+ -+import java.io.ByteArrayOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.management.ManagementFactory; -+import java.lang.management.OperatingSystemMXBean; -+import java.lang.management.RuntimeMXBean; -+import java.net.HttpURLConnection; -+import java.net.InetAddress; -+import java.net.URL; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+import java.util.logging.Level; -+import java.util.zip.GZIPOutputStream; -+ -+import static co.aikar.timings.TimingsManager.HISTORY; -+import static co.aikar.util.JSONUtil.appendObjectData; -+import static co.aikar.util.JSONUtil.createObject; -+import static co.aikar.util.JSONUtil.pair; -+import static co.aikar.util.JSONUtil.toArray; -+import static co.aikar.util.JSONUtil.toArrayMapper; -+import static co.aikar.util.JSONUtil.toObjectMapper; -+import static net.kyori.adventure.text.Component.text; -+ -+@SuppressWarnings({"rawtypes", "SuppressionAnnotation"}) -+@Deprecated(forRemoval = true) -+public class TimingsExport extends Thread { -+ -+ private final TimingsReportListener listeners; -+ private final Map out; -+ private final TimingHistory[] history; -+ private static long lastReport = 0; -+ -+ private TimingsExport(TimingsReportListener listeners, Map out, TimingHistory[] history) { -+ super("Timings paste thread"); -+ this.listeners = listeners; -+ this.out = out; -+ this.history = history; -+ } -+ -+ /** -+ * Checks if any pending reports are being requested, and builds one if needed. -+ */ -+ public static void reportTimings() { -+ if (Timings.requestingReport.isEmpty()) { -+ return; -+ } -+ TimingsReportListener listeners = new TimingsReportListener(Timings.requestingReport); -+ listeners.addConsoleIfNeeded(); -+ -+ Timings.requestingReport.clear(); -+ long now = System.currentTimeMillis(); -+ final long lastReportDiff = now - lastReport; -+ if (lastReportDiff < 60000) { -+ listeners.sendMessage(text("Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)", NamedTextColor.RED)); -+ listeners.done(); -+ return; -+ } -+ final long lastStartDiff = now - TimingsManager.timingStart; -+ if (lastStartDiff < 180000) { -+ listeners.sendMessage(text("Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)", NamedTextColor.RED)); -+ listeners.done(); -+ return; -+ } -+ listeners.sendMessage(text("Preparing Timings Report...", NamedTextColor.GREEN)); -+ lastReport = now; -+ Map parent = createObject( -+ // Get some basic system details about the server -+ pair("version", Bukkit.getVersion()), -+ pair("maxplayers", Bukkit.getMaxPlayers()), -+ pair("start", TimingsManager.timingStart / 1000), -+ pair("end", System.currentTimeMillis() / 1000), -+ pair("online-mode", Bukkit.getServer().getOnlineMode()), -+ pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000), -+ pair("datapacks", toArrayMapper(MinecraftServer.getServer().getPackRepository().getSelectedPacks(), pack -> { -+ return PlainTextComponentSerializer.plainText().serialize(PaperAdventure.asAdventure(pack.getChatLink(true))); -+ })) -+ ); -+ if (!TimingsManager.privacy) { -+ appendObjectData(parent, -+ pair("server", Bukkit.getUnsafe().getTimingsServerName()), -+ pair("motd", Bukkit.getServer().getMotd()), -+ pair("icon", Bukkit.getServer().getServerIcon().getData()) -+ ); -+ } -+ -+ final Runtime runtime = Runtime.getRuntime(); -+ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); -+ -+ OperatingSystemMXBean osInfo = ManagementFactory.getOperatingSystemMXBean(); -+ -+ HardwareAbstractionLayer hardwareInfo = new SystemInfo().getHardware(); -+ -+ parent.put("system", createObject( -+ pair("timingcost", getCost()), -+ pair("loadavg", osInfo.getSystemLoadAverage()), -+ pair("name", System.getProperty("os.name")), -+ pair("version", System.getProperty("os.version")), -+ pair("jvmversion", System.getProperty("java.version")), -+ pair("jvmvendor", System.getProperty("java.vendor")), -+ pair("jvmvendorversion", System.getProperty("java.vendor.version")), -+ pair("arch", System.getProperty("os.arch")), -+ pair("maxmem", runtime.maxMemory()), -+ pair("memory", createObject( -+ pair("heap", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().toString()), -+ pair("nonheap", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().toString()), -+ pair("finalizing", ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount()) -+ )), -+ pair("cpu", runtime.availableProcessors()), -+ pair("cpuname", hardwareInfo.getProcessor().getProcessorIdentifier().getName().trim()), -+ pair("runtime", runtimeBean.getUptime()), -+ pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")), -+ pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), input -> pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime())))) -+ ) -+ ); -+ -+ parent.put("worlds", toObjectMapper(MinecraftServer.getServer().getAllLevels(), world -> { -+ if (world.getWorld().getName().equals("worldeditregentempworld")) return null; -+ return pair(world.getWorld().getName(), createObject( -+ pair("gamerules", toObjectMapper(world.getWorld().getGameRules(), rule -> { -+ return pair(rule, world.getWorld().getGameRuleValue(rule)); -+ })), -+ pair("ticking-distance", world.getWorld().getSimulationDistance()), -+ pair("no-ticking-distance", world.getWorld().getViewDistance()), -+ pair("sending-distance", world.getWorld().getSendViewDistance()) -+ )); -+ })); -+ -+ Set tileEntityTypeSet = Sets.newHashSet(); -+ Set entityTypeSet = Sets.newHashSet(); -+ -+ int size = HISTORY.size(); -+ TimingHistory[] history = new TimingHistory[size + 1]; -+ int i = 0; -+ for (TimingHistory timingHistory : HISTORY) { -+ tileEntityTypeSet.addAll(timingHistory.tileEntityTypeSet); -+ entityTypeSet.addAll(timingHistory.entityTypeSet); -+ history[i++] = timingHistory; -+ } -+ -+ history[i] = new TimingHistory(); // Current snapshot -+ tileEntityTypeSet.addAll(history[i].tileEntityTypeSet); -+ entityTypeSet.addAll(history[i].entityTypeSet); -+ -+ -+ Map handlers = createObject(); -+ Map groupData; -+ synchronized (TimingIdentifier.GROUP_MAP) { -+ for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) { -+ synchronized (group.handlers) { -+ for (TimingHandler id : group.handlers) { -+ -+ if (!id.isTimed() && !id.isSpecial()) { -+ continue; -+ } -+ -+ String name = id.identifier.name; -+ if (name.startsWith("##")) { -+ name = name.substring(3); -+ } -+ handlers.put(id.id, toArray( -+ group.id, -+ name -+ )); -+ } -+ } -+ } -+ -+ groupData = toObjectMapper( -+ TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name)); -+ } -+ -+ parent.put("idmap", createObject( -+ pair("groups", groupData), -+ pair("handlers", handlers), -+ pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))), -+ pair("tileentity", -+ toObjectMapper(tileEntityTypeSet, input -> pair(input.ordinal(), input.name()))), -+ pair("entity", -+ toObjectMapper(entityTypeSet, input -> pair(input.ordinal(), input.name()))) -+ )); -+ -+ // Information about loaded plugins -+ -+ parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(), -+ plugin -> pair(plugin.getName(), createObject( -+ pair("version", plugin.getDescription().getVersion()), -+ pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()), -+ pair("website", plugin.getDescription().getWebsite()), -+ pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", ")) -+ )))); -+ -+ -+ -+ // Information on the users Config -+ -+ parent.put("config", createObject( -+ pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), -+ pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), -+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) -+ )); -+ -+ new TimingsExport(listeners, parent, history).start(); -+ } -+ -+ static long getCost() { -+ // Benchmark the users System.nanotime() for cost basis -+ int passes = 100; -+ TimingHandler SAMPLER1 = Timings.ofSafe("Timings Sampler 1"); -+ TimingHandler SAMPLER2 = Timings.ofSafe("Timings Sampler 2"); -+ TimingHandler SAMPLER3 = Timings.ofSafe("Timings Sampler 3"); -+ TimingHandler SAMPLER4 = Timings.ofSafe("Timings Sampler 4"); -+ TimingHandler SAMPLER5 = Timings.ofSafe("Timings Sampler 5"); -+ TimingHandler SAMPLER6 = Timings.ofSafe("Timings Sampler 6"); -+ -+ long start = System.nanoTime(); -+ for (int i = 0; i < passes; i++) { -+ SAMPLER1.startTiming(); -+ SAMPLER2.startTiming(); -+ SAMPLER3.startTiming(); -+ SAMPLER3.stopTiming(); -+ SAMPLER4.startTiming(); -+ SAMPLER5.startTiming(); -+ SAMPLER6.startTiming(); -+ SAMPLER6.stopTiming(); -+ SAMPLER5.stopTiming(); -+ SAMPLER4.stopTiming(); -+ SAMPLER2.stopTiming(); -+ SAMPLER1.stopTiming(); -+ } -+ long timingsCost = (System.nanoTime() - start) / passes / 6; -+ SAMPLER1.reset(true); -+ SAMPLER2.reset(true); -+ SAMPLER3.reset(true); -+ SAMPLER4.reset(true); -+ SAMPLER5.reset(true); -+ SAMPLER6.reset(true); -+ return timingsCost; -+ } -+ -+ private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) { -+ -+ JSONObject object = new JSONObject(); -+ for (String key : config.getKeys(false)) { -+ String fullKey = (parentKey != null ? parentKey + "." + key : key); -+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) { -+ continue; -+ } -+ final Object val = config.get(key); -+ -+ object.put(key, valAsJSON(val, fullKey)); -+ } -+ return object; -+ } -+ -+ private static Object valAsJSON(Object val, final String parentKey) { -+ if (!(val instanceof MemorySection)) { -+ if (val instanceof List) { -+ Iterable v = (Iterable) val; -+ return toArrayMapper(v, input -> valAsJSON(input, parentKey)); -+ } else { -+ return String.valueOf(val); -+ } -+ } else { -+ return mapAsJSON((ConfigurationSection) val, parentKey); -+ } -+ } -+ -+ @Override -+ public void run() { -+ out.put("data", toArrayMapper(history, TimingHistory::export)); -+ -+ -+ String response = null; -+ String timingsURL = null; -+ try { -+ HttpURLConnection con = (HttpURLConnection) new URL(TimingsManager.url + "post").openConnection(); -+ con.setDoOutput(true); -+ String hostName = "BrokenHost"; -+ try { -+ hostName = InetAddress.getLocalHost().getHostName(); -+ } catch (Exception ignored) {} -+ con.setRequestProperty("User-Agent", "Paper/" + Bukkit.getUnsafe().getTimingsServerName() + "/" + hostName); -+ con.setRequestMethod("POST"); -+ con.setInstanceFollowRedirects(false); -+ -+ OutputStream request = new GZIPOutputStream(con.getOutputStream()) {{ -+ this.def.setLevel(7); -+ }}; -+ -+ request.write(JSONValue.toJSONString(out).getBytes("UTF-8")); -+ request.close(); -+ -+ response = getResponse(con); -+ -+ if (con.getResponseCode() != 302) { -+ listeners.sendMessage(text( "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage(), NamedTextColor.RED)); -+ listeners.sendMessage(text("Check your logs for more information", NamedTextColor.RED)); -+ if (response != null) { -+ Bukkit.getLogger().log(Level.SEVERE, response); -+ } -+ return; -+ } -+ -+ timingsURL = con.getHeaderField("Location"); -+ listeners.sendMessage(text("View Timings Report: ", NamedTextColor.GREEN).append(text(timingsURL).clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, timingsURL)))); -+ -+ if (response != null && !response.isEmpty()) { -+ Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response); -+ } -+ } catch (IOException ex) { -+ listeners.sendMessage(text("Error uploading timings, check your logs for more information", NamedTextColor.RED)); -+ if (response != null) { -+ Bukkit.getLogger().log(Level.SEVERE, response); -+ } -+ Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex); -+ } finally { -+ this.listeners.done(timingsURL); -+ } -+ } -+ -+ private String getResponse(HttpURLConnection con) throws IOException { -+ InputStream is = null; -+ try { -+ is = con.getInputStream(); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ -+ byte[] b = new byte[1024]; -+ int bytesRead; -+ while ((bytesRead = is.read(b)) != -1) { -+ bos.write(b, 0, bytesRead); -+ } -+ return bos.toString(); -+ -+ } catch (IOException ex) { -+ listeners.sendMessage(text("Error uploading timings, check your logs for more information", NamedTextColor.RED)); -+ Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex); -+ return null; -+ } finally { -+ if (is != null) { -+ is.close(); -+ } -+ } -+ } -+} -diff --git a/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/src/main/java/co/aikar/timings/WorldTimingsHandler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2f0d9b953802dee821cfde82d22b0567cce8ee91 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/WorldTimingsHandler.java -@@ -0,0 +1,120 @@ -+package co.aikar.timings; -+ -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.storage.PrimaryLevelData; -+ -+/** -+ * Set of timers per world, to track world specific timings. -+ */ -+// TODO: Re-implement missing timers -+@Deprecated(forRemoval = true) -+public class WorldTimingsHandler { -+ public final Timing mobSpawn; -+ public final Timing doChunkUnload; -+ public final Timing doPortalForcer; -+ public final Timing scheduledBlocks; -+ public final Timing scheduledBlocksCleanup; -+ public final Timing scheduledBlocksTicking; -+ public final Timing chunkTicks; -+ public final Timing lightChunk; -+ public final Timing chunkTicksBlocks; -+ public final Timing doVillages; -+ public final Timing doChunkMap; -+ public final Timing doChunkMapUpdate; -+ public final Timing doChunkMapToUpdate; -+ public final Timing doChunkMapSortMissing; -+ public final Timing doChunkMapSortSendToPlayers; -+ public final Timing doChunkMapPlayersNeedingChunks; -+ public final Timing doChunkMapPendingSendToPlayers; -+ public final Timing doChunkMapUnloadChunks; -+ public final Timing doChunkGC; -+ public final Timing doSounds; -+ public final Timing entityRemoval; -+ public final Timing entityTick; -+ public final Timing tileEntityTick; -+ public final Timing tileEntityPending; -+ public final Timing tracker1; -+ public final Timing tracker2; -+ public final Timing doTick; -+ public final Timing tickEntities; -+ public final Timing chunks; -+ public final Timing newEntities; -+ public final Timing raids; -+ public final Timing chunkProviderTick; -+ public final Timing broadcastChunkUpdates; -+ public final Timing countNaturalMobs; -+ -+ public final Timing chunkLoad; -+ public final Timing chunkLoadPopulate; -+ public final Timing syncChunkLoad; -+ public final Timing chunkLoadLevelTimer; -+ public final Timing chunkIO; -+ public final Timing chunkPostLoad; -+ public final Timing worldSave; -+ public final Timing worldSaveChunks; -+ public final Timing worldSaveLevel; -+ public final Timing chunkSaveData; -+ -+ -+ public final Timing miscMobSpawning; -+ -+ public WorldTimingsHandler(Level server) { -+ String name = ((PrimaryLevelData) server.getLevelData()).getLevelName() + " - "; -+ -+ mobSpawn = Timings.ofSafe(name + "mobSpawn"); -+ doChunkUnload = Timings.ofSafe(name + "doChunkUnload"); -+ scheduledBlocks = Timings.ofSafe(name + "Scheduled Blocks"); -+ scheduledBlocksCleanup = Timings.ofSafe(name + "Scheduled Blocks - Cleanup"); -+ scheduledBlocksTicking = Timings.ofSafe(name + "Scheduled Blocks - Ticking"); -+ chunkTicks = Timings.ofSafe(name + "Chunk Ticks"); -+ lightChunk = Timings.ofSafe(name + "Light Chunk"); -+ chunkTicksBlocks = Timings.ofSafe(name + "Chunk Ticks - Blocks"); -+ doVillages = Timings.ofSafe(name + "doVillages"); -+ doChunkMap = Timings.ofSafe(name + "doChunkMap"); -+ doChunkMapUpdate = Timings.ofSafe(name + "doChunkMap - Update"); -+ doChunkMapToUpdate = Timings.ofSafe(name + "doChunkMap - To Update"); -+ doChunkMapSortMissing = Timings.ofSafe(name + "doChunkMap - Sort Missing"); -+ doChunkMapSortSendToPlayers = Timings.ofSafe(name + "doChunkMap - Sort Send To Players"); -+ doChunkMapPlayersNeedingChunks = Timings.ofSafe(name + "doChunkMap - Players Needing Chunks"); -+ doChunkMapPendingSendToPlayers = Timings.ofSafe(name + "doChunkMap - Pending Send To Players"); -+ doChunkMapUnloadChunks = Timings.ofSafe(name + "doChunkMap - Unload Chunks"); -+ doSounds = Timings.ofSafe(name + "doSounds"); -+ doChunkGC = Timings.ofSafe(name + "doChunkGC"); -+ doPortalForcer = Timings.ofSafe(name + "doPortalForcer"); -+ entityTick = Timings.ofSafe(name + "entityTick"); -+ entityRemoval = Timings.ofSafe(name + "entityRemoval"); -+ tileEntityTick = Timings.ofSafe(name + "tileEntityTick"); -+ tileEntityPending = Timings.ofSafe(name + "tileEntityPending"); -+ -+ chunkLoad = Timings.ofSafe(name + "Chunk Load"); -+ chunkLoadPopulate = Timings.ofSafe(name + "Chunk Load - Populate"); -+ syncChunkLoad = Timings.ofSafe(name + "Sync Chunk Load"); -+ chunkLoadLevelTimer = Timings.ofSafe(name + "Chunk Load - Load Level"); -+ chunkIO = Timings.ofSafe(name + "Chunk Load - DiskIO"); -+ chunkPostLoad = Timings.ofSafe(name + "Chunk Load - Post Load"); -+ worldSave = Timings.ofSafe(name + "World Save"); -+ worldSaveLevel = Timings.ofSafe(name + "World Save - Level"); -+ worldSaveChunks = Timings.ofSafe(name + "World Save - Chunks"); -+ chunkSaveData = Timings.ofSafe(name + "Chunk Save - Data"); -+ -+ tracker1 = Timings.ofSafe(name + "tracker stage 1"); -+ tracker2 = Timings.ofSafe(name + "tracker stage 2"); -+ doTick = Timings.ofSafe(name + "doTick"); -+ tickEntities = Timings.ofSafe(name + "tickEntities"); -+ -+ chunks = Timings.ofSafe(name + "Chunks"); -+ newEntities = Timings.ofSafe(name + "New entity registration"); -+ raids = Timings.ofSafe(name + "Raids"); -+ chunkProviderTick = Timings.ofSafe(name + "Chunk provider tick"); -+ broadcastChunkUpdates = Timings.ofSafe(name + "Broadcast chunk updates"); -+ countNaturalMobs = Timings.ofSafe(name + "Count natural mobs"); -+ -+ -+ miscMobSpawning = Timings.ofSafe(name + "Mob spawning - Misc"); -+ } -+ -+ public static Timing getTickList(ServerLevel worldserver, String timingsType) { -+ return Timings.ofSafe(((PrimaryLevelData) worldserver.getLevelData()).getLevelName() + " - Scheduled " + timingsType); -+ } -+} -diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -index f7197f1347251a37dd0f6d9ffa2f09bc3a4e1233..d0d36a57ec4896bcb74970f8fb24d8f3e17db133 100644 ---- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java -+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -@@ -31,7 +31,8 @@ public class PacketUtils { - engine.executeIfPossible(() -> { - if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players - if (listener.shouldHandleMessage(packet)) { -- try { -+ co.aikar.timings.Timing timing = co.aikar.timings.MinecraftTimings.getPacketTiming(packet); // Paper - timings -+ try (co.aikar.timings.Timing ignored = timing.startTiming()) { // Paper - timings - packet.handle(listener); - } catch (Exception exception) { - if (exception instanceof ReportedException) { -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3322865949fe5ddaab2dffc39260b75093f0f204..a76e2f5d29315d21212ff121f0047bf1140ad5ef 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -203,7 +203,7 @@ import org.bukkit.craftbukkit.Main; - import org.bukkit.event.server.ServerLoadEvent; - // CraftBukkit end - --import org.bukkit.craftbukkit.SpigotTimings; // Spigot -+import co.aikar.timings.MinecraftTimings; // Paper - - public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource { - -@@ -926,6 +926,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -- return !this.haveTime(); -+ return !this.canSleepForTickNoOversleep(); // Paper - move oversleep into full server tick - }); - } finally { - this.waitingForNextTick = false; -@@ -1371,6 +1384,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -+ return !this.canOversleep(); -+ }); -+ isOversleep = false;MinecraftTimings.serverOversleep.stopTiming(); -+ // Paper end -+ - ++this.tickCount; - this.tickRateManager.tick(); - this.tickChildren(shouldKeepTicking); -@@ -1409,6 +1430,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - entityplayer.connection.suspendFlushing(); - }); -- SpigotTimings.schedulerTimer.startTiming(); // Spigot -+ MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper - this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit -- SpigotTimings.schedulerTimer.stopTiming(); // Spigot -+ MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper - io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper - gameprofilerfiller.push("commandFunctions"); -- SpigotTimings.commandFunctionsTimer.startTiming(); // Spigot -+ MinecraftTimings.commandFunctionsTimer.startTiming(); // Spigot // Paper - this.getFunctions().tick(); -- SpigotTimings.commandFunctionsTimer.stopTiming(); // Spigot -+ MinecraftTimings.commandFunctionsTimer.stopTiming(); // Spigot // Paper - gameprofilerfiller.popPush("levels"); - Iterator iterator = this.getAllLevels().iterator(); - - // CraftBukkit start - // Run tasks that are waiting on processing -- SpigotTimings.processQueueTimer.startTiming(); // Spigot -+ MinecraftTimings.processQueueTimer.startTiming(); // Spigot - while (!this.processQueue.isEmpty()) { - this.processQueue.remove().run(); - } -- SpigotTimings.processQueueTimer.stopTiming(); // Spigot -+ MinecraftTimings.processQueueTimer.stopTiming(); // Spigot - -- SpigotTimings.timeUpdateTimer.startTiming(); // Spigot -+ MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper - // Send time updates to everyone, it will get the right time from the world the player is in. - if (this.tickCount % 20 == 0) { - for (int i = 0; i < this.getPlayerList().players.size(); ++i) { -@@ -1533,7 +1556,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop command = new java.util.concurrent.atomic.AtomicReference<>(s); // Paper - this.executeBlocking(() -> { - CommandSourceStack wrapper = rconConsoleSource.createCommandSourceStack(); - RemoteServerCommandEvent event = new RemoteServerCommandEvent(rconConsoleSource.getBukkitSender(wrapper), s); -@@ -702,9 +705,39 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - if (event.isCancelled()) { - return; - } -+ // Paper start -+ command.set(event.getCommand()); -+ if (event.getCommand().toLowerCase(java.util.Locale.ROOT).startsWith("timings") && event.getCommand().toLowerCase(java.util.Locale.ROOT).matches("timings (report|paste|get|merged|seperate)")) { -+ org.bukkit.command.BufferedCommandSender sender = new org.bukkit.command.BufferedCommandSender(); -+ Waitable waitable = new Waitable<>() { -+ @Override -+ protected String evaluate() { -+ return sender.getBuffer(); -+ } -+ }; -+ waitableArray[0] = waitable; -+ co.aikar.timings.Timings.generateReport(new co.aikar.timings.TimingsReportListener(sender, waitable)); -+ } else { -+ // Paper end - ConsoleInput serverCommand = new ConsoleInput(event.getCommand(), wrapper); - this.server.dispatchServerCommand(event.getSender(), serverCommand); -+ } // Paper - }); -+ // Paper start -+ if (waitableArray[0] != null) { -+ //noinspection unchecked -+ Waitable waitable = waitableArray[0]; -+ try { -+ return waitable.get(); -+ } catch (java.util.concurrent.ExecutionException e) { -+ throw new RuntimeException("Exception processing rcon command " + command.get(), e.getCause()); -+ } catch (InterruptedException e) { -+ Thread.currentThread().interrupt(); // Maintain interrupted state -+ throw new RuntimeException("Interrupted processing rcon command " + command.get(), e); -+ } -+ -+ } -+ // Paper end - return rconConsoleSource.getCommandResponse(); - // CraftBukkit end - } -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 3bb6eaabe8f62b556a52b83227b48f8324a9d0f0..30b28d9523820ed138c837ab9ee9bbb23c0dd285 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1,8 +1,10 @@ - package net.minecraft.server.level; - -+import co.aikar.timings.Timing; // Paper - import com.google.common.collect.ImmutableList; - import com.google.common.collect.ImmutableList.Builder; - import com.google.common.collect.Iterables; -+import com.google.common.collect.ComparisonChain; // Paper - import com.google.common.collect.Lists; - import com.google.common.collect.Queues; - import com.google.common.collect.Sets; -@@ -1355,6 +1357,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - List list = Lists.newArrayList(); - List list1 = this.level.players(); - ObjectIterator objectiterator = this.entityMap.values().iterator(); -+ level.timings.tracker1.startTiming(); // Paper - - ChunkMap.TrackedEntity playerchunkmap_entitytracker; - -@@ -1379,14 +1382,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - playerchunkmap_entitytracker.serverEntity.sendChanges(); - } - } -+ level.timings.tracker1.stopTiming(); // Paper - - if (!list.isEmpty()) { - objectiterator = this.entityMap.values().iterator(); - -+ level.timings.tracker2.startTiming(); // Paper - while (objectiterator.hasNext()) { - playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); - playerchunkmap_entitytracker.updatePlayers(list); - } -+ level.timings.tracker2.stopTiming(); // Paper - } - - } -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index c615510f3f59292715bcff1bd9e4e896c9733436..93422468474189343cdc1e29f06f6dfb12e4760a 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -207,13 +207,15 @@ public class ServerChunkCache extends ChunkSource { - } - - gameprofilerfiller.incrementCounter("getChunkCacheMiss"); -- this.level.timings.syncChunkLoadTimer.startTiming(); // Spigot - CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); - ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; - - Objects.requireNonNull(completablefuture); -+ if (!completablefuture.isDone()) { // Paper -+ this.level.timings.syncChunkLoad.startTiming(); // Paper - chunkproviderserver_b.managedBlock(completablefuture::isDone); -- this.level.timings.syncChunkLoadTimer.stopTiming(); // Spigot -+ this.level.timings.syncChunkLoad.stopTiming(); // Paper -+ } // Paper - ChunkResult chunkresult = (ChunkResult) completablefuture.join(); - ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error - -@@ -382,7 +384,9 @@ public class ServerChunkCache extends ChunkSource { - - public void save(boolean flush) { - this.runDistanceManagerUpdates(); -+ try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings - this.chunkMap.saveAllChunks(flush); -+ } // Paper - Timings - } - - @Override -@@ -429,10 +433,10 @@ public class ServerChunkCache extends ChunkSource { - this.level.timings.doChunkMap.stopTiming(); // Spigot - gameprofilerfiller.popPush("chunks"); - if (tickChunks) { -+ this.level.timings.chunks.startTiming(); // Paper - timings - this.tickChunks(); -- this.level.timings.tracker.startTiming(); // Spigot -+ this.level.timings.chunks.stopTiming(); // Paper - timings - this.chunkMap.tick(); -- this.level.timings.tracker.stopTiming(); // Spigot - } - - this.level.timings.doChunkUnload.startTiming(); // Spigot -@@ -481,7 +485,9 @@ public class ServerChunkCache extends ChunkSource { - LevelChunk chunk = playerchunk.getTickingChunk(); - - if (chunk != null) { -+ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing - playerchunk.broadcastChanges(chunk); -+ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing - } - } - -@@ -502,8 +508,10 @@ public class ServerChunkCache extends ChunkSource { - - private void tickChunks(ProfilerFiller profiler, long timeDelta, List chunks) { - profiler.popPush("naturalSpawnCount"); -+ this.level.timings.countNaturalMobs.startTiming(); // Paper - timings - int j = this.distanceManager.getNaturalSpawnChunkCount(); - NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(j, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)); -+ this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings - - this.lastSpawnState = spawnercreature_d; - profiler.popPush("spawnAndTick"); -@@ -531,15 +539,17 @@ public class ServerChunkCache extends ChunkSource { - } - - if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { -- this.level.timings.doTickTiles.startTiming(); // Spigot - this.level.tickChunk(chunk, k); -- this.level.timings.doTickTiles.stopTiming(); // Spigot - } - } - -+ this.level.timings.chunkTicks.stopTiming(); // Paper -+ - profiler.popPush("customSpawners"); - if (flag) { -+ try (co.aikar.timings.Timing ignored = this.level.timings.miscMobSpawning.startTiming()) { // Paper - timings - this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); -+ } - } - - } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index c6ded1ac73ddbc0336000f77c0f99fa20551a0de..a1565304c436258b561d97a6cc7aacecf68816b7 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1,6 +1,8 @@ - package net.minecraft.server.level; - - import com.google.common.annotations.VisibleForTesting; -+import co.aikar.timings.TimingHistory; // Paper -+import co.aikar.timings.Timings; // Paper - import com.google.common.collect.Lists; - import com.mojang.datafixers.DataFixer; - import com.mojang.datafixers.util.Pair; -@@ -176,7 +178,6 @@ import net.minecraft.world.ticks.LevelTicks; - import org.slf4j.Logger; - import org.bukkit.Bukkit; - import org.bukkit.WeatherType; --import org.bukkit.craftbukkit.SpigotTimings; // Spigot - import org.bukkit.craftbukkit.event.CraftEventFactory; - import org.bukkit.craftbukkit.generator.CustomWorldChunkManager; - import org.bukkit.craftbukkit.util.WorldUUID; -@@ -469,7 +470,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - gameprofilerfiller.push("tickPending"); -- this.timings.doTickPending.startTiming(); // Spigot -+ this.timings.scheduledBlocks.startTiming(); // Paper - if (!this.isDebug() && flag) { - j = this.getGameTime(); - gameprofilerfiller.push("blockTicks"); -@@ -478,15 +479,19 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.fluidTicks.tick(j, 65536, this::tickFluid); - gameprofilerfiller.pop(); - } -- this.timings.doTickPending.stopTiming(); // Spigot -+ this.timings.scheduledBlocks.stopTiming(); // Paper - - gameprofilerfiller.popPush("raid"); - if (flag) { -+ this.timings.raids.startTiming(); // Paper - timings - this.raids.tick(); -+ this.timings.raids.stopTiming(); // Paper - timings - } - - gameprofilerfiller.popPush("chunkSource"); -+ this.timings.chunkProviderTick.startTiming(); // Paper - timings - this.getChunkSource().tick(shouldKeepTicking, true); -+ this.timings.chunkProviderTick.stopTiming(); // Paper - timings - gameprofilerfiller.popPush("blockEvents"); - if (flag) { - this.timings.doSounds.startTiming(); // Spigot -@@ -635,6 +640,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - gameprofilerfiller.popPush("tickBlocks"); -+ timings.chunkTicksBlocks.startTiming(); // Paper - if (randomTickSpeed > 0) { - LevelChunkSection[] achunksection = chunk.getSections(); - -@@ -667,6 +673,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - } - -+ timings.chunkTicksBlocks.stopTiming(); // Paper - gameprofilerfiller.pop(); - } - -@@ -944,14 +951,22 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - public void tickNonPassenger(Entity entity) { -+ ++TimingHistory.entityTicks; // Paper - timings - // Spigot start -+ co.aikar.timings.Timing timer; // Paper - if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { - entity.tickCount++; -+ timer = entity.getType().inactiveTickTimer.startTiming(); try { // Paper - timings - entity.inactiveTick(); -+ } finally { timer.stopTiming(); } // Paper - return; - } - // Spigot end -- entity.tickTimer.startTiming(); // Spigot -+ // Paper start- timings -+ TimingHistory.activatedEntityTicks++; -+ timer = entity.getVehicle() != null ? entity.getType().passengerTickTimer.startTiming() : entity.getType().tickTimer.startTiming(); -+ try { -+ // Paper end - timings - entity.setOldPosAndRot(); - ProfilerFiller gameprofilerfiller = Profiler.get(); - -@@ -970,7 +985,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - this.tickPassenger(entity, entity1); - } -- entity.tickTimer.stopTiming(); // Spigot -+ } finally { timer.stopTiming(); } // Paper - timings - - } - -@@ -1012,6 +1027,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - if (!savingDisabled) { - org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit -+ try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { // Paper - if (progressListener != null) { - progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); - } -@@ -1021,7 +1037,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - progressListener.progressStage(Component.translatable("menu.savingChunks")); - } - -+ timings.worldSaveChunks.startTiming(); // Paper - chunkproviderserver.save(flush); -+ timings.worldSaveChunks.stopTiming(); // Paper -+ }// Paper - if (flush) { - this.entityManager.saveAll(); - } else { -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 18d56058073b6cc4f9020f0a6137e4ac26eed0b2..d8fd2103a40d278c7ee4135c19dea3eb4534dda8 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -339,7 +339,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - @Override - public void tick() { -- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.startTiming(); // Spigot - if (this.ackBlockChangesUpTo > -1) { - this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); - this.ackBlockChangesUpTo = -1; -@@ -395,7 +394,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 - this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling")); - } -- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.stopTiming(); // Spigot - - } - -@@ -2122,7 +2120,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - private void handleCommand(String s) { -- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.startTiming(); // Spigot -+ co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper - if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot - this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); - -@@ -2132,7 +2130,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.cserver.getPluginManager().callEvent(event); - - if (event.isCancelled()) { -- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot -+ co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper - return; - } - -@@ -2145,7 +2143,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - java.util.logging.Logger.getLogger(ServerGamePacketListenerImpl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); - return; - } finally { -- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot -+ co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper - } - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 56f046bac04205a813441907058c4ce21982d927..b103d49458330be9f7fb3382c764b204a02a925a 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1,5 +1,6 @@ - package net.minecraft.server.players; - -+import co.aikar.timings.MinecraftTimings; - import com.google.common.collect.Lists; - import com.google.common.collect.Maps; - import com.google.common.collect.Sets; -@@ -976,10 +977,11 @@ public abstract class PlayerList { - } - - public void saveAll() { -+ MinecraftTimings.savePlayers.startTiming(); // Paper - for (int i = 0; i < this.players.size(); ++i) { - this.save((ServerPlayer) this.players.get(i)); - } -- -+ MinecraftTimings.savePlayers.stopTiming(); // Paper - } - - public UserWhiteList getWhiteList() { -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index c010d18061f58a583c69e85fc29305497523f569..c8b8102d84119dfb6093f4b79aa3124c594f9a88 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -148,7 +148,6 @@ import org.bukkit.command.CommandSender; - import org.bukkit.entity.Hanging; - import org.bukkit.entity.LivingEntity; - import org.bukkit.entity.Vehicle; --import org.spigotmc.CustomTimingsHandler; // Spigot - import org.bukkit.event.entity.EntityCombustByEntityEvent; - import org.bukkit.event.hanging.HangingBreakByEntityEvent; - import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; -@@ -326,7 +325,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - // Marks an entity, that it was removed by a plugin via Entity#remove - // Main use case currently is for SPIGOT-7487, preventing dropping of leash when leash is removed - public boolean pluginRemoved = false; -- public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getEntityTimings(this); // Spigot - // Spigot start - public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this); - public final boolean defaultActivationState; -@@ -866,7 +864,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public void move(MoverType type, Vec3 movement) { -- org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.startTiming(); // Spigot - if (this.noPhysics) { - this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); - } else { -@@ -978,7 +975,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - gameprofilerfiller.pop(); - } - } -- org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.stopTiming(); // Spigot - } - - private void applyMovementEmissionAndPlaySound(Entity.MovementEmission moveEffect, Vec3 movement, BlockPos landingPos, BlockState landingState) { -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 17ab230c95901f0533997ac117d5b3d852fcd467..970161efa46b3a71ddae665f9df5966c70fd3471 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -413,6 +413,15 @@ public class EntityType implements FeatureElement, EntityTypeT - } - - public EntityType(EntityType.EntityFactory factory, MobCategory spawnGroup, boolean saveable, boolean summonable, boolean fireImmune, boolean spawnableFarFromPlayer, ImmutableSet canSpawnInside, EntityDimensions dimensions, float spawnBoxScale, int maxTrackDistance, int trackTickInterval, String translationKey, Optional> lootTable, FeatureFlagSet requiredFeatures) { -+ // Paper start -+ this(factory, spawnGroup, saveable, summonable, fireImmune, spawnableFarFromPlayer, canSpawnInside, dimensions, spawnBoxScale, maxTrackDistance, trackTickInterval, translationKey, lootTable, requiredFeatures, "custom"); -+ } -+ public EntityType(EntityType.EntityFactory factory, MobCategory spawnGroup, boolean saveable, boolean summonable, boolean fireImmune, boolean spawnableFarFromPlayer, ImmutableSet canSpawnInside, EntityDimensions dimensions, float spawnBoxScale, int maxTrackDistance, int trackTickInterval, String translationKey, Optional> lootTable, FeatureFlagSet requiredFeatures, String id) { -+ this.tickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "tick"); -+ this.inactiveTickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "inactiveTick"); -+ this.passengerTickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "passengerTick"); -+ this.passengerInactiveTickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "passengerInactiveTick"); -+ // Paper end - this.builtInRegistryHolder = BuiltInRegistries.ENTITY_TYPE.createIntrusiveHolder(this); - this.factory = factory; - this.category = spawnGroup; -@@ -720,6 +729,12 @@ public class EntityType implements FeatureElement, EntityTypeT - return this.updateInterval; - } - -+ // Paper start - timings -+ public final co.aikar.timings.Timing tickTimer; -+ public final co.aikar.timings.Timing inactiveTickTimer; -+ public final co.aikar.timings.Timing passengerTickTimer; -+ public final co.aikar.timings.Timing passengerInactiveTickTimer; -+ // Paper end - public boolean trackDeltas() { - return this != EntityType.PLAYER && this != EntityType.LLAMA_SPIT && this != EntityType.WITHER && this != EntityType.BAT && this != EntityType.ITEM_FRAME && this != EntityType.GLOW_ITEM_FRAME && this != EntityType.LEASH_KNOT && this != EntityType.PAINTING && this != EntityType.END_CRYSTAL && this != EntityType.EVOKER_FANGS; - } -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 9aa4e70f1d1c4de2138d31701dceaed25062e69c..6cc86412d45186dff312d9b1246fd1d03dbc15d8 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -162,7 +162,7 @@ import org.bukkit.event.entity.EntityTeleportEvent; - import org.bukkit.event.player.PlayerItemConsumeEvent; - // CraftBukkit end - --import org.bukkit.craftbukkit.SpigotTimings; // Spigot -+import co.aikar.timings.MinecraftTimings; // Paper - - public abstract class LivingEntity extends Entity implements Attackable { - -@@ -3090,7 +3090,6 @@ public abstract class LivingEntity extends Entity implements Attackable { - - @Override - public void tick() { -- SpigotTimings.timerEntityBaseTick.startTiming(); // Spigot - super.tick(); - this.updatingUsingItem(); - this.updateSwimAmount(); -@@ -3132,9 +3131,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - if (!this.isRemoved()) { -- SpigotTimings.timerEntityBaseTick.stopTiming(); // Spigot - this.aiStep(); -- SpigotTimings.timerEntityTickRest.startTiming(); // Spigot - } - - double d0 = this.getX() - this.xo; -@@ -3228,7 +3225,6 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - this.elytraAnimationState.tick(); -- SpigotTimings.timerEntityTickRest.stopTiming(); // Spigot - } - - public void detectEquipmentUpdatesPublic() { // CraftBukkit -@@ -3435,7 +3431,6 @@ public abstract class LivingEntity extends Entity implements Attackable { - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push("ai"); -- SpigotTimings.timerEntityAI.startTiming(); // Spigot - if (this.isImmobile()) { - this.jumping = false; - this.xxa = 0.0F; -@@ -3445,7 +3440,6 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.serverAiStep(); - gameprofilerfiller.pop(); - } -- SpigotTimings.timerEntityAI.stopTiming(); // Spigot - - gameprofilerfiller.pop(); - gameprofilerfiller.push("jump"); -@@ -3488,7 +3482,6 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.resetFallDistance(); - } - -- SpigotTimings.timerEntityAIMove.startTiming(); // Spigot - label112: - { - LivingEntity entityliving = this.getControllingPassenger(); -@@ -3502,7 +3495,6 @@ public abstract class LivingEntity extends Entity implements Attackable { - - this.travel(vec3d1); - } -- SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot - - if (!this.level().isClientSide() || this.isControlledByLocalInstance()) { - this.applyEffectsFromBlocks(); -@@ -3538,9 +3530,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox()); - } - -- SpigotTimings.timerEntityAICollision.startTiming(); // Spigot - this.pushEntities(); -- SpigotTimings.timerEntityAICollision.stopTiming(); // Spigot - gameprofilerfiller.pop(); - world = this.level(); - if (world instanceof ServerLevel worldserver) { -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 3fb17bbcecf6dc4af3b231835adff25f86e1379f..5df862e026e15e10e2fcc7c5a49e8a8022125579 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -95,7 +95,6 @@ import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePa - import org.bukkit.Bukkit; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.craftbukkit.CraftWorld; --import org.bukkit.craftbukkit.SpigotTimings; // Spigot - import org.bukkit.craftbukkit.block.CapturedBlockState; - import org.bukkit.craftbukkit.block.CraftBlockState; - import org.bukkit.craftbukkit.block.data.CraftBlockData; -@@ -165,7 +164,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - // Paper end - add paper world config - -- public final SpigotTimings.WorldTimingsHandler timings; // Spigot -+ public final co.aikar.timings.WorldTimingsHandler timings; // Paper - public static BlockPos lastPhysicsProblem; // Spigot - private org.spigotmc.TickLimiter entityLimiter; - private org.spigotmc.TickLimiter tileLimiter; -@@ -259,7 +258,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {} - }); - // CraftBukkit end -- this.timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings -+ this.timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings - this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime); - this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); - } -@@ -725,15 +724,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - - this.timings.tileEntityTick.stopTiming(); // Spigot - this.tickingBlockEntities = false; -+ co.aikar.timings.TimingHistory.tileEntityTicks += this.blockEntityTickers.size(); // Paper - gameprofilerfiller.pop(); - this.spigotConfig.currentPrimedTnt = 0; // Spigot - } - - public void guardEntityTick(Consumer tickConsumer, T entity) { - try { -- SpigotTimings.tickEntityTimer.startTiming(); // Spigot - tickConsumer.accept(entity); -- SpigotTimings.tickEntityTimer.stopTiming(); // Spigot - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity"); - CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked"); -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 27cbec37c6ea278232970ae035795fdecca71735..3cefda12d4c2ca2c4e9ef97eff961a55af164d6b 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -88,6 +88,15 @@ public class Block extends BlockBehaviour implements ItemLike { - public static final int UPDATE_LIMIT = 512; - protected final StateDefinition stateDefinition; - private BlockState defaultBlockState; -+ // Paper start -+ public co.aikar.timings.Timing timing; -+ public co.aikar.timings.Timing getTiming() { -+ if (timing == null) { -+ timing = co.aikar.timings.MinecraftTimings.getBlockTiming(this); -+ } -+ return timing; -+ } -+ // Paper end - @Nullable - private Item item; - private static final int CACHE_SIZE = 256; -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 4c3bc3a495990bc486fce7ba1758bf731c3baf02..9afe509b3455a7aabd11976fb8a7430d1bce065d 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -34,10 +34,12 @@ import org.bukkit.inventory.InventoryHolder; - // CraftBukkit end - - import org.spigotmc.CustomTimingsHandler; // Spigot -+import co.aikar.timings.MinecraftTimings; // Paper -+import co.aikar.timings.Timing; // Paper - - public abstract class BlockEntity { - -- public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot -+ public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper - // CraftBukkit start - data containers - private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); - public CraftPersistentDataContainer persistentDataContainer; -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index d76591694c3b167b8b8f17b61a373a43140a8b68..717e4bf9f5ee0ec2c3a0b5cc65a50b0f6d649a8d 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -627,6 +627,7 @@ public class LevelChunk extends ChunkAccess { - server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); - - if (this.needsDecoration) { -+ try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper - this.needsDecoration = false; - java.util.Random random = new java.util.Random(); - random.setSeed(this.level.getSeed()); -@@ -646,6 +647,7 @@ public class LevelChunk extends ChunkAccess { - } - } - server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); -+ } // Paper - } - } - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index d1b82dec25069a7027aaf53086b1829e511fc301..4367ccc628bb4f404d6a081083002518442f462b 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -@@ -576,15 +576,12 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun - @Nullable - private static LevelChunk.PostLoadProcessor postLoadChunk(ServerLevel world, List entities, List blockEntities) { - return entities.isEmpty() && blockEntities.isEmpty() ? null : (chunk) -> { -- world.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot - if (!entities.isEmpty()) { - world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD)); - } -- world.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot - - Iterator iterator = blockEntities.iterator(); - -- world.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot - while (iterator.hasNext()) { - CompoundTag nbttagcompound = (CompoundTag) iterator.next(); - boolean flag = nbttagcompound.getBoolean("keepPacked"); -@@ -600,7 +597,6 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun - } - } - } -- world.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot - - }; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 9bf8c4d9154c433e586f59587e8d7db7c310bb9c..232a21080ff416ac5b9fdf913f6784eb3bcdacfa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -379,7 +379,7 @@ public final class CraftServer implements Server { - this.saveCommandsConfig(); - this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); - this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); -- this.pluginManager.useTimings(this.configuration.getBoolean("settings.plugin-profiling")); -+ //this.pluginManager.useTimings(this.configuration.getBoolean("settings.plugin-profiling")); // Paper - we already moved this - this.overrideSpawnLimits(); - console.autosavePeriod = this.configuration.getInt("ticks-per.autosave"); - this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose")); -@@ -2636,12 +2636,31 @@ public final class CraftServer implements Server { - private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot() - { - -+ @Deprecated - @Override - public YamlConfiguration getConfig() - { - return org.spigotmc.SpigotConfig.config; - } - -+ @Override -+ public YamlConfiguration getBukkitConfig() -+ { -+ return configuration; -+ } -+ -+ @Override -+ public YamlConfiguration getSpigotConfig() -+ { -+ return org.spigotmc.SpigotConfig.config; -+ } -+ -+ @Override -+ public YamlConfiguration getPaperConfig() -+ { -+ return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); -+ } -+ - @Override - public void restart() { - org.spigotmc.RestartCommand.restart(); -diff --git a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java -deleted file mode 100644 -index b0ffa23faf62629043dfd613315eaf9c5fcc2cfe..0000000000000000000000000000000000000000 ---- a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java -+++ /dev/null -@@ -1,163 +0,0 @@ --package org.bukkit.craftbukkit; -- --import java.util.HashMap; --import net.minecraft.world.entity.Entity; --import net.minecraft.world.level.Level; --import net.minecraft.world.level.block.entity.BlockEntity; --import net.minecraft.world.level.storage.PrimaryLevelData; --import org.bukkit.craftbukkit.scheduler.CraftTask; --import org.bukkit.plugin.java.JavaPluginLoader; --import org.bukkit.scheduler.BukkitTask; --import org.spigotmc.CustomTimingsHandler; -- --public class SpigotTimings { -- -- public static final CustomTimingsHandler serverTickTimer = new CustomTimingsHandler("** Full Server Tick"); -- public static final CustomTimingsHandler playerListTimer = new CustomTimingsHandler("Player List"); -- public static final CustomTimingsHandler commandFunctionsTimer = new CustomTimingsHandler("Command Functions"); -- public static final CustomTimingsHandler connectionTimer = new CustomTimingsHandler("Connection Handler"); -- public static final CustomTimingsHandler playerConnectionTimer = new CustomTimingsHandler("** PlayerConnection"); -- public static final CustomTimingsHandler tickablesTimer = new CustomTimingsHandler("Tickables"); -- public static final CustomTimingsHandler schedulerTimer = new CustomTimingsHandler("Scheduler"); -- public static final CustomTimingsHandler timeUpdateTimer = new CustomTimingsHandler("Time Update"); -- public static final CustomTimingsHandler serverCommandTimer = new CustomTimingsHandler("Server Command"); -- public static final CustomTimingsHandler worldSaveTimer = new CustomTimingsHandler("World Save"); -- -- public static final CustomTimingsHandler entityMoveTimer = new CustomTimingsHandler("** entityMove"); -- public static final CustomTimingsHandler tickEntityTimer = new CustomTimingsHandler("** tickEntity"); -- public static final CustomTimingsHandler activatedEntityTimer = new CustomTimingsHandler("** activatedTickEntity"); -- public static final CustomTimingsHandler tickTileEntityTimer = new CustomTimingsHandler("** tickTileEntity"); -- -- public static final CustomTimingsHandler timerEntityBaseTick = new CustomTimingsHandler("** livingEntityBaseTick"); -- public static final CustomTimingsHandler timerEntityAI = new CustomTimingsHandler("** livingEntityAI"); -- public static final CustomTimingsHandler timerEntityAICollision = new CustomTimingsHandler("** livingEntityAICollision"); -- public static final CustomTimingsHandler timerEntityAIMove = new CustomTimingsHandler("** livingEntityAIMove"); -- public static final CustomTimingsHandler timerEntityTickRest = new CustomTimingsHandler("** livingEntityTickRest"); -- -- public static final CustomTimingsHandler processQueueTimer = new CustomTimingsHandler("processQueue"); -- public static final CustomTimingsHandler schedulerSyncTimer = new CustomTimingsHandler("** Scheduler - Sync Tasks", JavaPluginLoader.pluginParentTimer); -- -- public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand"); -- -- public static final CustomTimingsHandler entityActivationCheckTimer = new CustomTimingsHandler("entityActivationCheck"); -- public static final CustomTimingsHandler checkIfActiveTimer = new CustomTimingsHandler("** checkIfActive"); -- -- public static final HashMap entityTypeTimingMap = new HashMap(); -- public static final HashMap tileEntityTypeTimingMap = new HashMap(); -- public static final HashMap pluginTaskTimingMap = new HashMap(); -- -- /** -- * Gets a timer associated with a plugins tasks. -- * @param task -- * @param period -- * @return -- */ -- public static CustomTimingsHandler getPluginTaskTimings(BukkitTask task, long period) { -- if (!task.isSync()) { -- return null; -- } -- String plugin; -- final CraftTask ctask = (CraftTask) task; -- -- if (task.getOwner() != null) { -- plugin = task.getOwner().getDescription().getFullName(); -- } else { -- plugin = "Unknown"; -- } -- String taskname = ctask.getTaskName(); -- -- String name = "Task: " + plugin + " Runnable: " + taskname; -- if (period > 0) { -- name += "(interval:" + period + ")"; -- } else { -- name += "(Single)"; -- } -- CustomTimingsHandler result = SpigotTimings.pluginTaskTimingMap.get(name); -- if (result == null) { -- result = new CustomTimingsHandler(name, SpigotTimings.schedulerSyncTimer); -- SpigotTimings.pluginTaskTimingMap.put(name, result); -- } -- return result; -- } -- -- /** -- * Get a named timer for the specified entity type to track type specific timings. -- * @param entity -- * @return -- */ -- public static CustomTimingsHandler getEntityTimings(Entity entity) { -- String entityType = entity.getClass().getName(); -- CustomTimingsHandler result = SpigotTimings.entityTypeTimingMap.get(entityType); -- if (result == null) { -- result = new CustomTimingsHandler("** tickEntity - " + entity.getClass().getSimpleName(), SpigotTimings.activatedEntityTimer); -- SpigotTimings.entityTypeTimingMap.put(entityType, result); -- } -- return result; -- } -- -- /** -- * Get a named timer for the specified tile entity type to track type specific timings. -- * @param entity -- * @return -- */ -- public static CustomTimingsHandler getTileEntityTimings(BlockEntity entity) { -- String entityType = entity.getClass().getName(); -- CustomTimingsHandler result = SpigotTimings.tileEntityTypeTimingMap.get(entityType); -- if (result == null) { -- result = new CustomTimingsHandler("** tickTileEntity - " + entity.getClass().getSimpleName(), SpigotTimings.tickTileEntityTimer); -- SpigotTimings.tileEntityTypeTimingMap.put(entityType, result); -- } -- return result; -- } -- -- /** -- * Set of timers per world, to track world specific timings. -- */ -- public static class WorldTimingsHandler { -- public final CustomTimingsHandler mobSpawn; -- public final CustomTimingsHandler doChunkUnload; -- public final CustomTimingsHandler doTickPending; -- public final CustomTimingsHandler doTickTiles; -- public final CustomTimingsHandler doChunkMap; -- public final CustomTimingsHandler doSounds; -- public final CustomTimingsHandler entityTick; -- public final CustomTimingsHandler tileEntityTick; -- public final CustomTimingsHandler tileEntityPending; -- public final CustomTimingsHandler tracker; -- public final CustomTimingsHandler doTick; -- public final CustomTimingsHandler tickEntities; -- -- public final CustomTimingsHandler syncChunkLoadTimer; -- public final CustomTimingsHandler syncChunkLoadStructuresTimer; -- public final CustomTimingsHandler syncChunkLoadEntitiesTimer; -- public final CustomTimingsHandler syncChunkLoadTileEntitiesTimer; -- public final CustomTimingsHandler syncChunkLoadTileTicksTimer; -- public final CustomTimingsHandler syncChunkLoadPostTimer; -- -- public WorldTimingsHandler(Level server) { -- String name = ((PrimaryLevelData) server.levelData).getLevelName() + " - "; -- -- this.mobSpawn = new CustomTimingsHandler("** " + name + "mobSpawn"); -- this.doChunkUnload = new CustomTimingsHandler("** " + name + "doChunkUnload"); -- this.doTickPending = new CustomTimingsHandler("** " + name + "doTickPending"); -- this.doTickTiles = new CustomTimingsHandler("** " + name + "doTickTiles"); -- this.doChunkMap = new CustomTimingsHandler("** " + name + "doChunkMap"); -- this.doSounds = new CustomTimingsHandler("** " + name + "doSounds"); -- this.entityTick = new CustomTimingsHandler("** " + name + "entityTick"); -- this.tileEntityTick = new CustomTimingsHandler("** " + name + "tileEntityTick"); -- this.tileEntityPending = new CustomTimingsHandler("** " + name + "tileEntityPending"); -- -- this.syncChunkLoadTimer = new CustomTimingsHandler("** " + name + "syncChunkLoad"); -- this.syncChunkLoadStructuresTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Structures"); -- this.syncChunkLoadEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Entities"); -- this.syncChunkLoadTileEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileEntities"); -- this.syncChunkLoadTileTicksTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileTicks"); -- this.syncChunkLoadPostTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Post"); -- -- -- this.tracker = new CustomTimingsHandler(name + "tracker"); -- this.doTick = new CustomTimingsHandler(name + "doTick"); -- this.tickEntities = new CustomTimingsHandler(name + "tickEntities"); -- } -- } --} -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 24631135f90bb74bf829160ed079e152573666a2..f7833cd528797ba46b001db5208c29eb11ae2529 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2809,6 +2809,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - CraftPlayer.this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundSystemChatPacket(components, position == net.md_5.bungee.api.ChatMessageType.ACTION_BAR)); - } -+ -+ // Paper start -+ @Override -+ public int getPing() -+ { -+ return CraftPlayer.this.getPing(); -+ } -+ // Paper end - }; - - public Player.Spigot spigot() -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index 6effe47b32a8551aa6f6b11bc0315714a119e199..4c376f67ae311b4fedea27b3475f9fb56054aec2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.scheduler; - -+import co.aikar.timings.MinecraftTimings; // Paper - import com.google.common.base.Preconditions; - import com.google.common.util.concurrent.ThreadFactoryBuilder; - import java.util.ArrayList; -@@ -271,7 +272,7 @@ public class CraftScheduler implements BukkitScheduler { - } - return false; - } -- }); -+ }){{this.timings=co.aikar.timings.MinecraftTimings.getCancelTasksTimer();}}; // Paper - this.handle(task, 0L); - for (CraftTask taskPending = this.head.getNext(); taskPending != null; taskPending = taskPending.getNext()) { - if (taskPending == task) { -@@ -306,7 +307,7 @@ public class CraftScheduler implements BukkitScheduler { - } - } - } -- }); -+ }){{this.timings=co.aikar.timings.MinecraftTimings.getCancelTasksTimer(plugin);}}; // Paper - this.handle(task, 0L); - for (CraftTask taskPending = this.head.getNext(); taskPending != null; taskPending = taskPending.getNext()) { - if (taskPending == task) { -@@ -413,9 +414,7 @@ public class CraftScheduler implements BukkitScheduler { - if (task.isSync()) { - this.currentTask = task; - try { -- task.timings.startTiming(); // Spigot - task.run(); -- task.timings.stopTiming(); // Spigot - } catch (final Throwable throwable) { - task.getOwner().getLogger().log( - Level.WARNING, -@@ -442,8 +441,10 @@ public class CraftScheduler implements BukkitScheduler { - this.runners.remove(task.getTaskId()); - } - } -+ MinecraftTimings.bukkitSchedulerFinishTimer.startTiming(); // Paper - this.pending.addAll(temp); - temp.clear(); -+ MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming(); // Paper - this.debugHead = this.debugHead.getNextHead(this.currentTick); - } - -@@ -480,6 +481,7 @@ public class CraftScheduler implements BukkitScheduler { - } - - private void parsePending() { -+ MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); - CraftTask head = this.head; - CraftTask task = head.getNext(); - CraftTask lastTask = head; -@@ -498,6 +500,7 @@ public class CraftScheduler implements BukkitScheduler { - task.setNext(null); - } - this.head = lastTask; -+ MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); - } - - private boolean isReady(final int currentTick) { -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java -index e4d1eb4a0ce2c9874922585f6bb0d9ead433fde1..ba369f3dcfdf498e971dc4405d39657a9b6e97cc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java -@@ -1,12 +1,15 @@ - package org.bukkit.craftbukkit.scheduler; - - import java.util.function.Consumer; -+ -+import co.aikar.timings.NullTimingHandler; - import org.bukkit.Bukkit; - import org.bukkit.plugin.Plugin; - import org.bukkit.scheduler.BukkitTask; - --import org.bukkit.craftbukkit.SpigotTimings; // Spigot - import org.spigotmc.CustomTimingsHandler; // Spigot -+import co.aikar.timings.MinecraftTimings; // Paper -+import co.aikar.timings.Timing; // Paper - - public class CraftTask implements BukkitTask, Runnable { // Spigot - -@@ -26,13 +29,13 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot - */ - private volatile long period; - private long nextRun; -- private final Runnable rTask; -- private final Consumer cTask; -+ public final Runnable rTask; // Paper -+ public final Consumer cTask; // Paper -+ public Timing timings; // Paper - private final Plugin plugin; - private final int id; - private final long createdAt = System.nanoTime(); - -- final CustomTimingsHandler timings; // Spigot - CraftTask() { - this(null, null, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); - } -@@ -58,7 +61,7 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot - } - this.id = id; - this.period = period; -- this.timings = this.isSync() ? SpigotTimings.getPluginTaskTimings(this, period) : null; // Spigot -+ timings = task != null ? MinecraftTimings.getPluginTaskTimings(this, period) : NullTimingHandler.NULL; // Paper - } - - @Override -@@ -78,11 +81,13 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot - - @Override - public void run() { -+ try (Timing ignored = timings.startTiming()) { // Paper - if (this.rTask != null) { - this.rTask.run(); - } else { - this.cTask.accept(this); - } -+ } // Paper - } - - long getCreatedAt() { -@@ -113,7 +118,7 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot - this.next = next; - } - -- Class getTaskClass() { -+ public Class getTaskClass() { // Paper - return (this.rTask != null) ? this.rTask.getClass() : ((this.cTask != null) ? this.cTask.getClass() : null); - } - -@@ -137,9 +142,4 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot - return true; - } - -- // Spigot start -- public String getTaskName() { -- return (this.getTaskClass() == null) ? "Unknown" : this.getTaskClass().getName(); -- } -- // Spigot end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java -index f97eccb6a17c7876e1e002d798eb67bbe80571a0..76effc345d362047e64d064eb64a5222612aec14 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java -@@ -8,4 +8,11 @@ public class CraftIconCache implements CachedServerIcon { - public CraftIconCache(final byte[] value) { - this.value = value; - } -+ -+ public String getData() { -+ if (value == null) { -+ return null; -+ } -+ return "data:image/png;base64," + new String(java.util.Base64.getEncoder().encode(value), java.nio.charset.StandardCharsets.UTF_8); -+ } // Paper - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 4b2377a1de608b9142a28c66389d04290f7c0330..0285349c0e882c1d928240a7ece2f9cc9f4122f2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -199,6 +199,12 @@ public final class CraftMagicNumbers implements UnsafeValues { - return CraftNamespacedKey.toMinecraft(mat.getKey()); - } - // ======================================================================== -+ // Paper start -+ @Override -+ public void reportTimings() { -+ co.aikar.timings.TimingsExport.reportTimings(); -+ } -+ // Paper end - - public static byte toLegacyData(BlockState data) { - return CraftLegacy.toLegacyData(data); -@@ -448,6 +454,12 @@ public final class CraftMagicNumbers implements UnsafeValues { - public DamageSource.Builder createDamageSourceBuilder(DamageType damageType) { - return new CraftDamageSourceBuilder(damageType); - } -+ // Paper start -+ @Override -+ public String getTimingsServerName() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().timings.serverName; -+ } -+ // Paper end - - @Override - public String get(Class aClass, String s) { -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 3591b79481ac17bd02e59ac3c623d1c6991abd84..2122e044d99902d2aff86693aaa424a50b9f8a13 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -27,7 +27,7 @@ import net.minecraft.world.entity.projectile.ThrownTrident; - import net.minecraft.world.entity.raid.Raider; - import net.minecraft.world.level.Level; - import net.minecraft.world.phys.AABB; --import org.bukkit.craftbukkit.SpigotTimings; -+import co.aikar.timings.MinecraftTimings; - - public class ActivationRange - { -@@ -74,8 +74,8 @@ public class ActivationRange - /** - * These entities are excluded from Activation range checks. - * -- * @param entity -- * @param config -+ * @param entity Entity to initialize -+ * @param config Spigot config to determine ranges - * @return boolean If it should always tick. - */ - public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config) -@@ -110,7 +110,7 @@ public class ActivationRange - */ - public static void activateEntities(Level world) - { -- SpigotTimings.entityActivationCheckTimer.startTiming(); -+ MinecraftTimings.entityActivationCheckTimer.startTiming(); - final int miscActivationRange = world.spigotConfig.miscActivationRange; - final int raiderActivationRange = world.spigotConfig.raiderActivationRange; - final int animalActivationRange = world.spigotConfig.animalActivationRange; -@@ -137,7 +137,7 @@ public class ActivationRange - - world.getEntities().get(ActivationRange.maxBB, ActivationRange::activateEntity); - } -- SpigotTimings.entityActivationCheckTimer.stopTiming(); -+ MinecraftTimings.entityActivationCheckTimer.stopTiming(); - } - - /** -@@ -232,10 +232,8 @@ public class ActivationRange - */ - public static boolean checkIfActive(Entity entity) - { -- SpigotTimings.checkIfActiveTimer.startTiming(); - // Never safe to skip fireworks or entities not yet added to chunk - if ( entity instanceof FireworkRocketEntity ) { -- SpigotTimings.checkIfActiveTimer.stopTiming(); - return true; - } - -@@ -259,7 +257,6 @@ public class ActivationRange - { - isActive = false; - } -- SpigotTimings.checkIfActiveTimer.stopTiming(); - return isActive; - } - } diff --git a/patches/server/0024-Further-improve-server-tick-loop.patch b/patches/server/0024-Further-improve-server-tick-loop.patch deleted file mode 100644 index 798d5e4b4d..0000000000 --- a/patches/server/0024-Further-improve-server-tick-loop.patch +++ /dev/null @@ -1,233 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 1 Mar 2016 23:09:29 -0600 -Subject: [PATCH] Further improve server tick loop - -Improves how the catchup buffer is handled, allowing it to roll both ways -increasing the effeciency of the thread sleep so it only will sleep once. - -Also increases the buffer of the catchup to ensure server stays at 20 TPS unless extreme conditions - -Previous implementation did not calculate TPS correctly. -Switch to a realistic rolling average and factor in std deviation as an extra reporting variable - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index a76e2f5d29315d21212ff121f0047bf1140ad5ef..31582d4f9d52c86cf834b9dc10e58b68c67f1272 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -307,7 +307,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); - public int autosavePeriod; - public Commands vanillaCommandDispatcher; -@@ -316,7 +316,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) { -+ sender.sendMessage(net.kyori.adventure.text.Component.text() -+ .append(net.kyori.adventure.text.Component.text("Current Memory Usage: ", net.kyori.adventure.text.format.NamedTextColor.GOLD)) -+ .append(net.kyori.adventure.text.Component.text(((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)", net.kyori.adventure.text.format.NamedTextColor.GREEN)) -+ ); -+ if (!this.hasShownMemoryWarning) { -+ sender.sendMessage(WARN_MSG); -+ this.hasShownMemoryWarning = true; -+ } - } -- sender.sendMessage( sb.substring( 0, sb.length() - 2 ) ); -- sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " -- + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)"); -+ // Paper end - - return true; - } - -- private String format(double tps) -+ private boolean hasShownMemoryWarning; // Paper -+ private static net.kyori.adventure.text.Component format(double tps) // Paper - Made static - { -- return ( ( tps > 18.0 ) ? ChatColor.GREEN : ( tps > 16.0 ) ? ChatColor.YELLOW : ChatColor.RED ).toString() -- + ( ( tps > 20.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 ); -+ // Paper -+ net.kyori.adventure.text.format.TextColor color = ( ( tps > 18.0 ) ? net.kyori.adventure.text.format.NamedTextColor.GREEN : ( tps > 16.0 ) ? net.kyori.adventure.text.format.NamedTextColor.YELLOW : net.kyori.adventure.text.format.NamedTextColor.RED ); -+ String amount = Math.min(Math.round(tps * 100.0) / 100.0, 20.0) + (tps > 21.0 ? "*" : ""); // Paper - only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise -+ return net.kyori.adventure.text.Component.text(amount, color); -+ // Paper end - } - } diff --git a/patches/server/0024-Remove-Spigot-timings.patch b/patches/server/0024-Remove-Spigot-timings.patch new file mode 100644 index 0000000000..6913a8e21f --- /dev/null +++ b/patches/server/0024-Remove-Spigot-timings.patch @@ -0,0 +1,967 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 3 Mar 2016 04:00:11 -0600 +Subject: [PATCH] Remove Spigot timings + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 4a573e8b7cd90f65c190982662e92a11f79a1d3e..709c6361aa5eb78071ce9d0f2a65ce8a56af1443 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -203,7 +203,6 @@ import org.bukkit.craftbukkit.Main; + import org.bukkit.event.server.ServerLoadEvent; + // CraftBukkit end + +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot + + public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource { + +@@ -1456,7 +1455,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + entityplayer.connection.suspendFlushing(); + }); +- SpigotTimings.schedulerTimer.startTiming(); // Spigot + this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit +- SpigotTimings.schedulerTimer.stopTiming(); // Spigot + io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper + gameprofilerfiller.push("commandFunctions"); +- SpigotTimings.commandFunctionsTimer.startTiming(); // Spigot + this.getFunctions().tick(); +- SpigotTimings.commandFunctionsTimer.stopTiming(); // Spigot + gameprofilerfiller.popPush("levels"); + Iterator iterator = this.getAllLevels().iterator(); + + // CraftBukkit start + // Run tasks that are waiting on processing +- SpigotTimings.processQueueTimer.startTiming(); // Spigot + while (!this.processQueue.isEmpty()) { + this.processQueue.remove().run(); + } +- SpigotTimings.processQueueTimer.stopTiming(); // Spigot + +- SpigotTimings.timeUpdateTimer.startTiming(); // Spigot + // Send time updates to everyone, it will get the right time from the world the player is in. + if (this.tickCount % 20 == 0) { + for (int i = 0; i < this.getPlayerList().players.size(); ++i) { +@@ -1596,7 +1584,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); + ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; + + Objects.requireNonNull(completablefuture); + chunkproviderserver_b.managedBlock(completablefuture::isDone); +- this.level.timings.syncChunkLoadTimer.stopTiming(); // Spigot + ChunkResult chunkresult = (ChunkResult) completablefuture.join(); + ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error + +@@ -420,25 +418,19 @@ public class ServerChunkCache extends ChunkSource { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("purge"); +- this.level.timings.doChunkMap.startTiming(); // Spigot + if (this.level.tickRateManager().runsNormally() || !tickChunks || this.level.spigotConfig.unloadFrozenChunks) { // Spigot + this.distanceManager.purgeStaleTickets(); + } + + this.runDistanceManagerUpdates(); +- this.level.timings.doChunkMap.stopTiming(); // Spigot + gameprofilerfiller.popPush("chunks"); + if (tickChunks) { + this.tickChunks(); +- this.level.timings.tracker.startTiming(); // Spigot + this.chunkMap.tick(); +- this.level.timings.tracker.stopTiming(); // Spigot + } + +- this.level.timings.doChunkUnload.startTiming(); // Spigot + gameprofilerfiller.popPush("unload"); + this.chunkMap.tick(shouldKeepTicking); +- this.level.timings.doChunkUnload.stopTiming(); // Spigot + gameprofilerfiller.pop(); + this.clearCache(); + } +@@ -531,9 +523,7 @@ public class ServerChunkCache extends ChunkSource { + } + + if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { +- this.level.timings.doTickTiles.startTiming(); // Spigot + this.level.tickChunk(chunk, k); +- this.level.timings.doTickTiles.stopTiming(); // Spigot + } + } + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index c6ded1ac73ddbc0336000f77c0f99fa20551a0de..f3633da64f990972cddc03f2fcfd34ced2955a7a 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -176,7 +176,6 @@ import net.minecraft.world.ticks.LevelTicks; + import org.slf4j.Logger; + import org.bukkit.Bukkit; + import org.bukkit.WeatherType; +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot + import org.bukkit.craftbukkit.event.CraftEventFactory; + import org.bukkit.craftbukkit.generator.CustomWorldChunkManager; + import org.bukkit.craftbukkit.util.WorldUUID; +@@ -469,7 +468,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + + gameprofilerfiller.push("tickPending"); +- this.timings.doTickPending.startTiming(); // Spigot + if (!this.isDebug() && flag) { + j = this.getGameTime(); + gameprofilerfiller.push("blockTicks"); +@@ -478,7 +476,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.fluidTicks.tick(j, 65536, this::tickFluid); + gameprofilerfiller.pop(); + } +- this.timings.doTickPending.stopTiming(); // Spigot + + gameprofilerfiller.popPush("raid"); + if (flag) { +@@ -489,9 +486,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.getChunkSource().tick(shouldKeepTicking, true); + gameprofilerfiller.popPush("blockEvents"); + if (flag) { +- this.timings.doSounds.startTiming(); // Spigot + this.runBlockEvents(); +- this.timings.doSounds.stopTiming(); // Spigot + } + + this.handlingTick = false; +@@ -504,7 +499,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + if (flag1 || this.emptyTime++ < 300) { + gameprofilerfiller.push("entities"); +- this.timings.tickEntities.startTiming(); // Spigot + if (this.dragonFight != null && flag) { + gameprofilerfiller.push("dragonFight"); + this.dragonFight.tick(); +@@ -512,7 +506,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + + org.spigotmc.ActivationRange.activateEntities(this); // Spigot +- this.timings.entityTick.startTiming(); // Spigot + this.entityTickList.forEach((entity) -> { + if (!entity.isRemoved()) { + if (!tickratemanager.isEntityFrozen(entity)) { +@@ -537,8 +530,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + } + }); +- this.timings.entityTick.stopTiming(); // Spigot +- this.timings.tickEntities.stopTiming(); // Spigot + gameprofilerfiller.pop(); + this.tickBlockEntities(); + } +@@ -951,7 +942,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + return; + } + // Spigot end +- entity.tickTimer.startTiming(); // Spigot + entity.setOldPosAndRot(); + ProfilerFiller gameprofilerfiller = Profiler.get(); + +@@ -970,7 +960,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + this.tickPassenger(entity, entity1); + } +- entity.tickTimer.stopTiming(); // Spigot + + } + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 18d56058073b6cc4f9020f0a6137e4ac26eed0b2..fddc6b5abbad66ebe556ff8565c38c60b7883fce 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -339,7 +339,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + @Override + public void tick() { +- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.startTiming(); // Spigot + if (this.ackBlockChangesUpTo > -1) { + this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); + this.ackBlockChangesUpTo = -1; +@@ -395,7 +394,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 + this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling")); + } +- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.stopTiming(); // Spigot + + } + +@@ -2122,7 +2120,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + + private void handleCommand(String s) { +- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.startTiming(); // Spigot + if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot + this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); + +@@ -2132,7 +2129,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.cserver.getPluginManager().callEvent(event); + + if (event.isCancelled()) { +- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot + return; + } + +@@ -2145,7 +2141,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + java.util.logging.Logger.getLogger(ServerGamePacketListenerImpl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + return; + } finally { +- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot + } + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index c010d18061f58a583c69e85fc29305497523f569..c8b8102d84119dfb6093f4b79aa3124c594f9a88 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -148,7 +148,6 @@ import org.bukkit.command.CommandSender; + import org.bukkit.entity.Hanging; + import org.bukkit.entity.LivingEntity; + import org.bukkit.entity.Vehicle; +-import org.spigotmc.CustomTimingsHandler; // Spigot + import org.bukkit.event.entity.EntityCombustByEntityEvent; + import org.bukkit.event.hanging.HangingBreakByEntityEvent; + import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; +@@ -326,7 +325,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + // Marks an entity, that it was removed by a plugin via Entity#remove + // Main use case currently is for SPIGOT-7487, preventing dropping of leash when leash is removed + public boolean pluginRemoved = false; +- public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getEntityTimings(this); // Spigot + // Spigot start + public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this); + public final boolean defaultActivationState; +@@ -866,7 +864,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public void move(MoverType type, Vec3 movement) { +- org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.startTiming(); // Spigot + if (this.noPhysics) { + this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); + } else { +@@ -978,7 +975,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + gameprofilerfiller.pop(); + } + } +- org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.stopTiming(); // Spigot + } + + private void applyMovementEmissionAndPlaySound(Entity.MovementEmission moveEffect, Vec3 movement, BlockPos landingPos, BlockState landingState) { +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 9aa4e70f1d1c4de2138d31701dceaed25062e69c..6dba567e9f7a197af16598647f216b5323d1b601 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -162,8 +162,6 @@ import org.bukkit.event.entity.EntityTeleportEvent; + import org.bukkit.event.player.PlayerItemConsumeEvent; + // CraftBukkit end + +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot +- + public abstract class LivingEntity extends Entity implements Attackable { + + private static final Logger LOGGER = LogUtils.getLogger(); +@@ -3090,7 +3088,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + + @Override + public void tick() { +- SpigotTimings.timerEntityBaseTick.startTiming(); // Spigot + super.tick(); + this.updatingUsingItem(); + this.updateSwimAmount(); +@@ -3132,9 +3129,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + if (!this.isRemoved()) { +- SpigotTimings.timerEntityBaseTick.stopTiming(); // Spigot + this.aiStep(); +- SpigotTimings.timerEntityTickRest.startTiming(); // Spigot + } + + double d0 = this.getX() - this.xo; +@@ -3228,7 +3223,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + this.elytraAnimationState.tick(); +- SpigotTimings.timerEntityTickRest.stopTiming(); // Spigot + } + + public void detectEquipmentUpdatesPublic() { // CraftBukkit +@@ -3435,7 +3429,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("ai"); +- SpigotTimings.timerEntityAI.startTiming(); // Spigot + if (this.isImmobile()) { + this.jumping = false; + this.xxa = 0.0F; +@@ -3445,7 +3438,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.serverAiStep(); + gameprofilerfiller.pop(); + } +- SpigotTimings.timerEntityAI.stopTiming(); // Spigot + + gameprofilerfiller.pop(); + gameprofilerfiller.push("jump"); +@@ -3488,7 +3480,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.resetFallDistance(); + } + +- SpigotTimings.timerEntityAIMove.startTiming(); // Spigot + label112: + { + LivingEntity entityliving = this.getControllingPassenger(); +@@ -3502,7 +3493,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + + this.travel(vec3d1); + } +- SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot + + if (!this.level().isClientSide() || this.isControlledByLocalInstance()) { + this.applyEffectsFromBlocks(); +@@ -3538,9 +3528,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox()); + } + +- SpigotTimings.timerEntityAICollision.startTiming(); // Spigot + this.pushEntities(); +- SpigotTimings.timerEntityAICollision.stopTiming(); // Spigot + gameprofilerfiller.pop(); + world = this.level(); + if (world instanceof ServerLevel worldserver) { +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 3fb17bbcecf6dc4af3b231835adff25f86e1379f..c5e480c43668211a091e44ae50b40b025ff1dca9 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -95,7 +95,6 @@ import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePa + import org.bukkit.Bukkit; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.craftbukkit.CraftWorld; +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot + import org.bukkit.craftbukkit.block.CapturedBlockState; + import org.bukkit.craftbukkit.block.CraftBlockState; + import org.bukkit.craftbukkit.block.data.CraftBlockData; +@@ -165,7 +164,6 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + } + // Paper end - add paper world config + +- public final SpigotTimings.WorldTimingsHandler timings; // Spigot + public static BlockPos lastPhysicsProblem; // Spigot + private org.spigotmc.TickLimiter entityLimiter; + private org.spigotmc.TickLimiter tileLimiter; +@@ -259,7 +257,6 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {} + }); + // CraftBukkit end +- this.timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings + this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime); + this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); + } +@@ -692,15 +689,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("blockEntities"); +- this.timings.tileEntityPending.startTiming(); // Spigot + this.tickingBlockEntities = true; + if (!this.pendingBlockEntityTickers.isEmpty()) { + this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); + this.pendingBlockEntityTickers.clear(); + } +- this.timings.tileEntityPending.stopTiming(); // Spigot + +- this.timings.tileEntityTick.startTiming(); // Spigot + // Spigot start + // Iterator iterator = this.blockEntityTickers.iterator(); + boolean flag = this.tickRateManager().runsNormally(); +@@ -723,7 +717,6 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + } + } + +- this.timings.tileEntityTick.stopTiming(); // Spigot + this.tickingBlockEntities = false; + gameprofilerfiller.pop(); + this.spigotConfig.currentPrimedTnt = 0; // Spigot +@@ -731,9 +724,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + public void guardEntityTick(Consumer tickConsumer, T entity) { + try { +- SpigotTimings.tickEntityTimer.startTiming(); // Spigot + tickConsumer.accept(entity); +- SpigotTimings.tickEntityTimer.stopTiming(); // Spigot + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity"); + CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked"); +diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +index 1fe93e01c5e37397aded5d1f99214bf1bffe70b7..9389fd53f2bff0a9ca389694b312dc6da58befaf 100644 +--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java ++++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +@@ -148,7 +148,6 @@ public final class NaturalSpawner { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("spawner"); +- world.timings.mobSpawn.startTiming(); // Spigot + Iterator iterator = spawnableGroups.iterator(); + + while (iterator.hasNext()) { +@@ -163,7 +162,6 @@ public final class NaturalSpawner { + } + } + +- world.timings.mobSpawn.stopTiming(); // Spigot + gameprofilerfiller.pop(); + } + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +index 4c3bc3a495990bc486fce7ba1758bf731c3baf02..751a5ae04e4de3f5d85eda20092a87ef4f547436 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -33,11 +33,8 @@ import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; + import org.bukkit.inventory.InventoryHolder; + // CraftBukkit end + +-import org.spigotmc.CustomTimingsHandler; // Spigot +- + public abstract class BlockEntity { + +- public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot + // CraftBukkit start - data containers + private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); + public CraftPersistentDataContainer persistentDataContainer; +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +index d76591694c3b167b8b8f17b61a373a43140a8b68..f63d55bfe42b117c5b437e690124a98d94752a9a 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -971,7 +971,6 @@ public class LevelChunk extends ChunkAccess { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push(this::getType); +- this.blockEntity.tickTimer.startTiming(); // Spigot + BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); + + if (this.blockEntity.getType().isValid(iblockdata)) { +@@ -990,9 +989,6 @@ public class LevelChunk extends ChunkAccess { + this.blockEntity.fillCrashReportCategory(crashreportsystemdetails); + throw new ReportedException(crashreport); + // Spigot start +- } finally { +- this.blockEntity.tickTimer.stopTiming(); +- // Spigot end + } + } + } +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +index d1b82dec25069a7027aaf53086b1829e511fc301..4367ccc628bb4f404d6a081083002518442f462b 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +@@ -576,15 +576,12 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun + @Nullable + private static LevelChunk.PostLoadProcessor postLoadChunk(ServerLevel world, List entities, List blockEntities) { + return entities.isEmpty() && blockEntities.isEmpty() ? null : (chunk) -> { +- world.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot + if (!entities.isEmpty()) { + world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD)); + } +- world.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot + + Iterator iterator = blockEntities.iterator(); + +- world.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot + while (iterator.hasNext()) { + CompoundTag nbttagcompound = (CompoundTag) iterator.next(); + boolean flag = nbttagcompound.getBoolean("keepPacked"); +@@ -600,7 +597,6 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun + } + } + } +- world.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot + + }; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 7c5b0db8115dc4032a3a364299ca06c88efd9a26..5650b4cfcd4008ac7f351d5bfb1fb8cc81da4caa 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -379,7 +379,6 @@ public final class CraftServer implements Server { + this.saveCommandsConfig(); + this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); + this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); +- this.pluginManager.useTimings(this.configuration.getBoolean("settings.plugin-profiling")); + this.overrideSpawnLimits(); + console.autosavePeriod = this.configuration.getInt("ticks-per.autosave"); + this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose")); +@@ -2636,12 +2635,31 @@ public final class CraftServer implements Server { + private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot() + { + ++ @Deprecated + @Override + public YamlConfiguration getConfig() + { + return org.spigotmc.SpigotConfig.config; + } + ++ @Override ++ public YamlConfiguration getBukkitConfig() ++ { ++ return configuration; ++ } ++ ++ @Override ++ public YamlConfiguration getSpigotConfig() ++ { ++ return org.spigotmc.SpigotConfig.config; ++ } ++ ++ @Override ++ public YamlConfiguration getPaperConfig() ++ { ++ return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); ++ } ++ + @Override + public void restart() { + org.spigotmc.RestartCommand.restart(); +diff --git a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java +deleted file mode 100644 +index b0ffa23faf62629043dfd613315eaf9c5fcc2cfe..0000000000000000000000000000000000000000 +--- a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java ++++ /dev/null +@@ -1,163 +0,0 @@ +-package org.bukkit.craftbukkit; +- +-import java.util.HashMap; +-import net.minecraft.world.entity.Entity; +-import net.minecraft.world.level.Level; +-import net.minecraft.world.level.block.entity.BlockEntity; +-import net.minecraft.world.level.storage.PrimaryLevelData; +-import org.bukkit.craftbukkit.scheduler.CraftTask; +-import org.bukkit.plugin.java.JavaPluginLoader; +-import org.bukkit.scheduler.BukkitTask; +-import org.spigotmc.CustomTimingsHandler; +- +-public class SpigotTimings { +- +- public static final CustomTimingsHandler serverTickTimer = new CustomTimingsHandler("** Full Server Tick"); +- public static final CustomTimingsHandler playerListTimer = new CustomTimingsHandler("Player List"); +- public static final CustomTimingsHandler commandFunctionsTimer = new CustomTimingsHandler("Command Functions"); +- public static final CustomTimingsHandler connectionTimer = new CustomTimingsHandler("Connection Handler"); +- public static final CustomTimingsHandler playerConnectionTimer = new CustomTimingsHandler("** PlayerConnection"); +- public static final CustomTimingsHandler tickablesTimer = new CustomTimingsHandler("Tickables"); +- public static final CustomTimingsHandler schedulerTimer = new CustomTimingsHandler("Scheduler"); +- public static final CustomTimingsHandler timeUpdateTimer = new CustomTimingsHandler("Time Update"); +- public static final CustomTimingsHandler serverCommandTimer = new CustomTimingsHandler("Server Command"); +- public static final CustomTimingsHandler worldSaveTimer = new CustomTimingsHandler("World Save"); +- +- public static final CustomTimingsHandler entityMoveTimer = new CustomTimingsHandler("** entityMove"); +- public static final CustomTimingsHandler tickEntityTimer = new CustomTimingsHandler("** tickEntity"); +- public static final CustomTimingsHandler activatedEntityTimer = new CustomTimingsHandler("** activatedTickEntity"); +- public static final CustomTimingsHandler tickTileEntityTimer = new CustomTimingsHandler("** tickTileEntity"); +- +- public static final CustomTimingsHandler timerEntityBaseTick = new CustomTimingsHandler("** livingEntityBaseTick"); +- public static final CustomTimingsHandler timerEntityAI = new CustomTimingsHandler("** livingEntityAI"); +- public static final CustomTimingsHandler timerEntityAICollision = new CustomTimingsHandler("** livingEntityAICollision"); +- public static final CustomTimingsHandler timerEntityAIMove = new CustomTimingsHandler("** livingEntityAIMove"); +- public static final CustomTimingsHandler timerEntityTickRest = new CustomTimingsHandler("** livingEntityTickRest"); +- +- public static final CustomTimingsHandler processQueueTimer = new CustomTimingsHandler("processQueue"); +- public static final CustomTimingsHandler schedulerSyncTimer = new CustomTimingsHandler("** Scheduler - Sync Tasks", JavaPluginLoader.pluginParentTimer); +- +- public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand"); +- +- public static final CustomTimingsHandler entityActivationCheckTimer = new CustomTimingsHandler("entityActivationCheck"); +- public static final CustomTimingsHandler checkIfActiveTimer = new CustomTimingsHandler("** checkIfActive"); +- +- public static final HashMap entityTypeTimingMap = new HashMap(); +- public static final HashMap tileEntityTypeTimingMap = new HashMap(); +- public static final HashMap pluginTaskTimingMap = new HashMap(); +- +- /** +- * Gets a timer associated with a plugins tasks. +- * @param task +- * @param period +- * @return +- */ +- public static CustomTimingsHandler getPluginTaskTimings(BukkitTask task, long period) { +- if (!task.isSync()) { +- return null; +- } +- String plugin; +- final CraftTask ctask = (CraftTask) task; +- +- if (task.getOwner() != null) { +- plugin = task.getOwner().getDescription().getFullName(); +- } else { +- plugin = "Unknown"; +- } +- String taskname = ctask.getTaskName(); +- +- String name = "Task: " + plugin + " Runnable: " + taskname; +- if (period > 0) { +- name += "(interval:" + period + ")"; +- } else { +- name += "(Single)"; +- } +- CustomTimingsHandler result = SpigotTimings.pluginTaskTimingMap.get(name); +- if (result == null) { +- result = new CustomTimingsHandler(name, SpigotTimings.schedulerSyncTimer); +- SpigotTimings.pluginTaskTimingMap.put(name, result); +- } +- return result; +- } +- +- /** +- * Get a named timer for the specified entity type to track type specific timings. +- * @param entity +- * @return +- */ +- public static CustomTimingsHandler getEntityTimings(Entity entity) { +- String entityType = entity.getClass().getName(); +- CustomTimingsHandler result = SpigotTimings.entityTypeTimingMap.get(entityType); +- if (result == null) { +- result = new CustomTimingsHandler("** tickEntity - " + entity.getClass().getSimpleName(), SpigotTimings.activatedEntityTimer); +- SpigotTimings.entityTypeTimingMap.put(entityType, result); +- } +- return result; +- } +- +- /** +- * Get a named timer for the specified tile entity type to track type specific timings. +- * @param entity +- * @return +- */ +- public static CustomTimingsHandler getTileEntityTimings(BlockEntity entity) { +- String entityType = entity.getClass().getName(); +- CustomTimingsHandler result = SpigotTimings.tileEntityTypeTimingMap.get(entityType); +- if (result == null) { +- result = new CustomTimingsHandler("** tickTileEntity - " + entity.getClass().getSimpleName(), SpigotTimings.tickTileEntityTimer); +- SpigotTimings.tileEntityTypeTimingMap.put(entityType, result); +- } +- return result; +- } +- +- /** +- * Set of timers per world, to track world specific timings. +- */ +- public static class WorldTimingsHandler { +- public final CustomTimingsHandler mobSpawn; +- public final CustomTimingsHandler doChunkUnload; +- public final CustomTimingsHandler doTickPending; +- public final CustomTimingsHandler doTickTiles; +- public final CustomTimingsHandler doChunkMap; +- public final CustomTimingsHandler doSounds; +- public final CustomTimingsHandler entityTick; +- public final CustomTimingsHandler tileEntityTick; +- public final CustomTimingsHandler tileEntityPending; +- public final CustomTimingsHandler tracker; +- public final CustomTimingsHandler doTick; +- public final CustomTimingsHandler tickEntities; +- +- public final CustomTimingsHandler syncChunkLoadTimer; +- public final CustomTimingsHandler syncChunkLoadStructuresTimer; +- public final CustomTimingsHandler syncChunkLoadEntitiesTimer; +- public final CustomTimingsHandler syncChunkLoadTileEntitiesTimer; +- public final CustomTimingsHandler syncChunkLoadTileTicksTimer; +- public final CustomTimingsHandler syncChunkLoadPostTimer; +- +- public WorldTimingsHandler(Level server) { +- String name = ((PrimaryLevelData) server.levelData).getLevelName() + " - "; +- +- this.mobSpawn = new CustomTimingsHandler("** " + name + "mobSpawn"); +- this.doChunkUnload = new CustomTimingsHandler("** " + name + "doChunkUnload"); +- this.doTickPending = new CustomTimingsHandler("** " + name + "doTickPending"); +- this.doTickTiles = new CustomTimingsHandler("** " + name + "doTickTiles"); +- this.doChunkMap = new CustomTimingsHandler("** " + name + "doChunkMap"); +- this.doSounds = new CustomTimingsHandler("** " + name + "doSounds"); +- this.entityTick = new CustomTimingsHandler("** " + name + "entityTick"); +- this.tileEntityTick = new CustomTimingsHandler("** " + name + "tileEntityTick"); +- this.tileEntityPending = new CustomTimingsHandler("** " + name + "tileEntityPending"); +- +- this.syncChunkLoadTimer = new CustomTimingsHandler("** " + name + "syncChunkLoad"); +- this.syncChunkLoadStructuresTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Structures"); +- this.syncChunkLoadEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Entities"); +- this.syncChunkLoadTileEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileEntities"); +- this.syncChunkLoadTileTicksTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileTicks"); +- this.syncChunkLoadPostTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Post"); +- +- +- this.tracker = new CustomTimingsHandler(name + "tracker"); +- this.doTick = new CustomTimingsHandler(name + "doTick"); +- this.tickEntities = new CustomTimingsHandler(name + "tickEntities"); +- } +- } +-} +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 24631135f90bb74bf829160ed079e152573666a2..f7833cd528797ba46b001db5208c29eb11ae2529 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2809,6 +2809,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + CraftPlayer.this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundSystemChatPacket(components, position == net.md_5.bungee.api.ChatMessageType.ACTION_BAR)); + } ++ ++ // Paper start ++ @Override ++ public int getPing() ++ { ++ return CraftPlayer.this.getPing(); ++ } ++ // Paper end + }; + + public Player.Spigot spigot() +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +index 6effe47b32a8551aa6f6b11bc0315714a119e199..2c36d0796714997191c6540c34a9df60718065f6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +@@ -413,9 +413,7 @@ public class CraftScheduler implements BukkitScheduler { + if (task.isSync()) { + this.currentTask = task; + try { +- task.timings.startTiming(); // Spigot + task.run(); +- task.timings.stopTiming(); // Spigot + } catch (final Throwable throwable) { + task.getOwner().getLogger().log( + Level.WARNING, +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +index e4d1eb4a0ce2c9874922585f6bb0d9ead433fde1..17680f112d0c7e7aee07e34477daa21ef2ddaa6f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +@@ -1,13 +1,11 @@ + package org.bukkit.craftbukkit.scheduler; + + import java.util.function.Consumer; ++ + import org.bukkit.Bukkit; + import org.bukkit.plugin.Plugin; + import org.bukkit.scheduler.BukkitTask; + +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot +-import org.spigotmc.CustomTimingsHandler; // Spigot +- + public class CraftTask implements BukkitTask, Runnable { // Spigot + + private volatile CraftTask next = null; +@@ -26,13 +24,12 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + */ + private volatile long period; + private long nextRun; +- private final Runnable rTask; +- private final Consumer cTask; ++ public final Runnable rTask; ++ public final Consumer cTask; + private final Plugin plugin; + private final int id; + private final long createdAt = System.nanoTime(); + +- final CustomTimingsHandler timings; // Spigot + CraftTask() { + this(null, null, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); + } +@@ -58,7 +55,6 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + } + this.id = id; + this.period = period; +- this.timings = this.isSync() ? SpigotTimings.getPluginTaskTimings(this, period) : null; // Spigot + } + + @Override +@@ -137,9 +133,4 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + return true; + } + +- // Spigot start +- public String getTaskName() { +- return (this.getTaskClass() == null) ? "Unknown" : this.getTaskClass().getName(); +- } +- // Spigot end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java +index f97eccb6a17c7876e1e002d798eb67bbe80571a0..dba31a2cbcfebe1f28883545ce4a70fcb9251aa6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java +@@ -1,6 +1,7 @@ + package org.bukkit.craftbukkit.util; + + import org.bukkit.util.CachedServerIcon; ++import org.jetbrains.annotations.Nullable; + + public class CraftIconCache implements CachedServerIcon { + public final byte[] value; +@@ -8,4 +9,12 @@ public class CraftIconCache implements CachedServerIcon { + public CraftIconCache(final byte[] value) { + this.value = value; + } ++ ++ @Override ++ public @Nullable String getData() { ++ if (this.value == null) { ++ return null; ++ } ++ return "data:image/png;base64," + new String(java.util.Base64.getEncoder().encode(this.value), java.nio.charset.StandardCharsets.UTF_8); ++ } + } +diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java +index 3591b79481ac17bd02e59ac3c623d1c6991abd84..263df52c7f5e172a6b9118b4bc4672e443adedba 100644 +--- a/src/main/java/org/spigotmc/ActivationRange.java ++++ b/src/main/java/org/spigotmc/ActivationRange.java +@@ -27,7 +27,6 @@ import net.minecraft.world.entity.projectile.ThrownTrident; + import net.minecraft.world.entity.raid.Raider; + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.AABB; +-import org.bukkit.craftbukkit.SpigotTimings; + + public class ActivationRange + { +@@ -110,7 +109,6 @@ public class ActivationRange + */ + public static void activateEntities(Level world) + { +- SpigotTimings.entityActivationCheckTimer.startTiming(); + final int miscActivationRange = world.spigotConfig.miscActivationRange; + final int raiderActivationRange = world.spigotConfig.raiderActivationRange; + final int animalActivationRange = world.spigotConfig.animalActivationRange; +@@ -137,7 +135,6 @@ public class ActivationRange + + world.getEntities().get(ActivationRange.maxBB, ActivationRange::activateEntity); + } +- SpigotTimings.entityActivationCheckTimer.stopTiming(); + } + + /** +@@ -232,10 +229,8 @@ public class ActivationRange + */ + public static boolean checkIfActive(Entity entity) + { +- SpigotTimings.checkIfActiveTimer.startTiming(); + // Never safe to skip fireworks or entities not yet added to chunk + if ( entity instanceof FireworkRocketEntity ) { +- SpigotTimings.checkIfActiveTimer.stopTiming(); + return true; + } + +@@ -259,7 +254,6 @@ public class ActivationRange + { + isActive = false; + } +- SpigotTimings.checkIfActiveTimer.stopTiming(); + return isActive; + } + } diff --git a/patches/server/0025-Add-command-line-option-to-load-extra-plugin-jars-no.patch b/patches/server/0025-Add-command-line-option-to-load-extra-plugin-jars-no.patch index ef3594f354..5e58214e0f 100644 --- a/patches/server/0025-Add-command-line-option-to-load-extra-plugin-jars-no.patch +++ b/patches/server/0025-Add-command-line-option-to-load-extra-plugin-jars-no.patch @@ -7,10 +7,10 @@ Subject: [PATCH] Add command line option to load extra plugin jars not in the ex: java -jar paperclip.jar nogui -add-plugin=/path/to/plugin.jar -add-plugin=/path/to/another/plugin_jar.jar diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index f7af198966928ac28bd7e2851caae93a27974e5c..10e1b6bf90b249a5dd04bb10f0a742cdedae0a01 100644 +index 5650b4cfcd4008ac7f351d5bfb1fb8cc81da4caa..db7cad60c8f805dd1b4089673f5f9d073a429a67 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -462,6 +462,35 @@ public final class CraftServer implements Server { +@@ -461,6 +461,35 @@ public final class CraftServer implements Server { io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.INSTANCE.enter(io.papermc.paper.plugin.entrypoint.Entrypoint.PLUGIN); // Paper - replace implementation } diff --git a/patches/server/0033-Expose-server-build-information.patch b/patches/server/0033-Expose-server-build-information.patch index b560e277bd..83f13af41a 100644 --- a/patches/server/0033-Expose-server-build-information.patch +++ b/patches/server/0033-Expose-server-build-information.patch @@ -533,7 +533,7 @@ index 0000000000000000000000000000000000000000..790bad0494454ca12ee152e3de6da3da + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 31582d4f9d52c86cf834b9dc10e58b68c67f1272..5ce80e72ed677b464e7e7b2dcb616cdcb399686b 100644 +index 709c6361aa5eb78071ce9d0f2a65ce8a56af1443..b86d8a3756cb8c1adb1aceda57f60b0ccdb3f659 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -45,7 +45,6 @@ import java.util.Set; @@ -553,7 +553,7 @@ index 31582d4f9d52c86cf834b9dc10e58b68c67f1272..5ce80e72ed677b464e7e7b2dcb616cdc import org.bukkit.event.server.ServerLoadEvent; // CraftBukkit end -@@ -1784,7 +1781,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java index f697d45e0ac4e9cdc8a46121510a04c0f294d91f..e086765dec32241bc5a77afcf072c77a40c6d785 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java diff --git a/patches/server/0036-Entity-Origin-API.patch b/patches/server/0036-Entity-Origin-API.patch index e1281dbfae..47721fa03d 100644 --- a/patches/server/0036-Entity-Origin-API.patch +++ b/patches/server/0036-Entity-Origin-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Entity Origin API diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a1565304c436258b561d97a6cc7aacecf68816b7..e2e949dbd8be52dc6a00414f0f79746ee554acd7 100644 +index f3633da64f990972cddc03f2fcfd34ced2955a7a..025363e6b51ff8aa089715b1ec2a0fa1caab65d6 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2212,6 +2212,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2182,6 +2182,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe entity.updateDynamicGameEventListener(DynamicGameEventListener::add); entity.inWorld = true; // CraftBukkit - Mark entity as in world entity.valid = true; // CraftBukkit diff --git a/patches/server/0037-Prevent-block-entity-and-entity-crashes.patch b/patches/server/0037-Prevent-block-entity-and-entity-crashes.patch index 01c8a71861..7226372683 100644 --- a/patches/server/0037-Prevent-block-entity-and-entity-crashes.patch +++ b/patches/server/0037-Prevent-block-entity-and-entity-crashes.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Prevent block entity and entity crashes diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 5df862e026e15e10e2fcc7c5a49e8a8022125579..d15c7ed69068ba5832c92860cae56ff4a96cd398 100644 +index c5e480c43668211a091e44ae50b40b025ff1dca9..071545e60f838fa6c930edc35f46e0ce9b73fb44 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -733,11 +733,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -726,11 +726,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { try { tickConsumer.accept(entity); } catch (Throwable throwable) { @@ -26,10 +26,10 @@ index 5df862e026e15e10e2fcc7c5a49e8a8022125579..d15c7ed69068ba5832c92860cae56ff4 } diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 9afe509b3455a7aabd11976fb8a7430d1bce065d..4536632687e71b02d5945cac3816b72ac540935e 100644 +index 751a5ae04e4de3f5d85eda20092a87ef4f547436..3d7c5db5514f9d4401da22d2df88c5614051e568 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -273,7 +273,12 @@ public abstract class BlockEntity { +@@ -268,7 +268,12 @@ public abstract class BlockEntity { public void fillCrashReportCategory(CrashReportCategory crashReportSection) { crashReportSection.setDetail("Name", this::getNameForReporting); if (this.level != null) { @@ -44,10 +44,10 @@ index 9afe509b3455a7aabd11976fb8a7430d1bce065d..4536632687e71b02d5945cac3816b72a } } diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 717e4bf9f5ee0ec2c3a0b5cc65a50b0f6d649a8d..e1cd7497b1355030bf44b53aa30400604dff9aca 100644 +index f63d55bfe42b117c5b437e690124a98d94752a9a..79cf3089c128ef3c17d956da1e380670279ee5da 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -986,11 +986,11 @@ public class LevelChunk extends ChunkAccess { +@@ -983,11 +983,11 @@ public class LevelChunk extends ChunkAccess { gameprofilerfiller.pop(); } catch (Throwable throwable) { @@ -62,5 +62,5 @@ index 717e4bf9f5ee0ec2c3a0b5cc65a50b0f6d649a8d..e1cd7497b1355030bf44b53aa3040060 + LevelChunk.this.removeBlockEntity(this.getPos()); + // Paper end - Prevent block entity and entity crashes // Spigot start - } finally { - this.blockEntity.tickTimer.stopTiming(); + } + } diff --git a/patches/server/0040-Add-more-entities-to-activation-range-ignore-list.patch b/patches/server/0040-Add-more-entities-to-activation-range-ignore-list.patch index 9eaf33d852..2c4e1fe578 100644 --- a/patches/server/0040-Add-more-entities-to-activation-range-ignore-list.patch +++ b/patches/server/0040-Add-more-entities-to-activation-range-ignore-list.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add more entities to activation range ignore list diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 2122e044d99902d2aff86693aaa424a50b9f8a13..5dac9bdb23de3d143cd678e583eaf6e8095bb209 100644 +index 263df52c7f5e172a6b9118b4bc4672e443adedba..dd1c5bc7522a4710cbfdd4764f6431e1e28d63cc 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -92,6 +92,9 @@ public class ActivationRange +@@ -91,6 +91,9 @@ public class ActivationRange || entity instanceof AbstractHurtingProjectile || entity instanceof LightningBolt || entity instanceof PrimedTnt diff --git a/patches/server/0043-Optimize-explosions.patch b/patches/server/0043-Optimize-explosions.patch index 78e4626f21..a5a1950402 100644 --- a/patches/server/0043-Optimize-explosions.patch +++ b/patches/server/0043-Optimize-explosions.patch @@ -10,10 +10,10 @@ This patch adds a per-tick cache that is used for storing and retrieving an entity's exposure during an explosion. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 5ce80e72ed677b464e7e7b2dcb616cdcb399686b..d04ce36f79523417c7c2b49a8324b52ef6a6f0f4 100644 +index b86d8a3756cb8c1adb1aceda57f60b0ccdb3f659..cc4c5fcbeca4862d8ff78b127cb3f2c07956dfaf 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -401,6 +401,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { diff --git a/patches/server/0052-Disable-spigot-tick-limiters.patch b/patches/server/0052-Disable-spigot-tick-limiters.patch index a588d23369..2872d59fb9 100644 --- a/patches/server/0052-Disable-spigot-tick-limiters.patch +++ b/patches/server/0052-Disable-spigot-tick-limiters.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Disable spigot tick limiters diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index a0b89abe50f4cea64f29e8957c535400658d4524..5fe8726af73eb5334f47046c93096341e987269b 100644 +index e90dac1e46bca60896b027f670ba521d67c02c1e..ed15f5c4a365a199d04e92d688035e4ab755e8db 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -706,9 +706,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -701,9 +701,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { boolean flag = this.tickRateManager().runsNormally(); int tilesThisCycle = 0; diff --git a/patches/server/0053-Fix-spawn-location-event-changing-location.patch b/patches/server/0053-Fix-spawn-location-event-changing-location.patch index 07448453cf..15086ed363 100644 --- a/patches/server/0053-Fix-spawn-location-event-changing-location.patch +++ b/patches/server/0053-Fix-spawn-location-event-changing-location.patch @@ -7,10 +7,10 @@ Subject: [PATCH] Fix spawn location event changing location public net.minecraft.world.entity.Entity setRot(FF)V diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b103d49458330be9f7fb3382c764b204a02a925a..2af4b853fde493c1fa5c8d530aae4d68b79f7ba0 100644 +index 56f046bac04205a813441907058c4ce21982d927..50b1e493a9adfa687dc22c66044c6aa243340b3f 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -235,7 +235,10 @@ public abstract class PlayerList { +@@ -234,7 +234,10 @@ public abstract class PlayerList { player.spawnIn(worldserver1); player.gameMode.setLevel((ServerLevel) player.level()); diff --git a/patches/server/0055-Improve-Player-chat-API-handling.patch b/patches/server/0055-Improve-Player-chat-API-handling.patch index c119f32750..8c63e9bdb4 100644 --- a/patches/server/0055-Improve-Player-chat-API-handling.patch +++ b/patches/server/0055-Improve-Player-chat-API-handling.patch @@ -17,7 +17,7 @@ Co-authored-by: Jake Potrebic Co-authored-by: SoSeDiK diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index d8fd2103a40d278c7ee4135c19dea3eb4534dda8..ab31b31c61d652275a667f34ab018e4c8d0cdc08 100644 +index fddc6b5abbad66ebe556ff8565c38c60b7883fce..55d61a4c93233c0d3994e75f41e29065c2f1ea93 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -2032,7 +2032,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @@ -29,21 +29,19 @@ index d8fd2103a40d278c7ee4135c19dea3eb4534dda8..ab31b31c61d652275a667f34ab018e4c this.handleCommand(s); } else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { // Do nothing, this is coming from a plugin -@@ -2119,7 +2119,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } +@@ -2120,6 +2120,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } -- private void handleCommand(String s) { -+ public void handleCommand(String s) { // Paper - private -> public + private void handleCommand(String s) { + org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + s); // Paper - Add async catcher - co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); + diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 9683759c36de3b9d791e56dc1fb993087c1bc37c..3b58cc979c4e2fb5382f0c67ccfaa8440e9c785b 100644 +index 2bfa790a9f0ca07217c9d9f7dd916950d859530c..ec0d7e44235378380b7180ca1a9ca56b14dac1c7 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -937,7 +937,7 @@ public final class CraftServer implements Server { +@@ -936,7 +936,7 @@ public final class CraftServer implements Server { public boolean dispatchCommand(CommandSender sender, String commandLine) { Preconditions.checkArgument(sender != null, "sender cannot be null"); Preconditions.checkArgument(commandLine != null, "commandLine cannot be null"); diff --git a/patches/server/0057-Expose-server-CommandMap.patch b/patches/server/0057-Expose-server-CommandMap.patch index b491a42083..bc0e6fd63e 100644 --- a/patches/server/0057-Expose-server-CommandMap.patch +++ b/patches/server/0057-Expose-server-CommandMap.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Expose server CommandMap diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 3b58cc979c4e2fb5382f0c67ccfaa8440e9c785b..89778f8df5a4b639bb0fe5e7a0164ef55b96041a 100644 +index ec0d7e44235378380b7180ca1a9ca56b14dac1c7..63573ec7e8f855a1afd892c9615a45c1bc742ac1 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2183,6 +2183,7 @@ public final class CraftServer implements Server { +@@ -2182,6 +2182,7 @@ public final class CraftServer implements Server { return this.helpMap; } diff --git a/patches/server/0061-Add-velocity-warnings.patch b/patches/server/0061-Add-velocity-warnings.patch index a8358fe2a4..aafd524684 100644 --- a/patches/server/0061-Add-velocity-warnings.patch +++ b/patches/server/0061-Add-velocity-warnings.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add velocity warnings diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 89778f8df5a4b639bb0fe5e7a0164ef55b96041a..c80fe475edffce53363dfea658b9f13a2c6de1ca 100644 +index 63573ec7e8f855a1afd892c9615a45c1bc742ac1..bb562ada45b828c79d83afdd1687edd32cbaf1dc 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -305,6 +305,7 @@ public final class CraftServer implements Server { diff --git a/patches/server/0062-Add-exception-reporting-event.patch b/patches/server/0062-Add-exception-reporting-event.patch index 17d813039c..52fe575b57 100644 --- a/patches/server/0062-Add-exception-reporting-event.patch +++ b/patches/server/0062-Add-exception-reporting-event.patch @@ -91,10 +91,10 @@ index a5b18a04f482d05d3ca74918a580499b21c2fc3c..bd3f71c3eaa33258ff56062ea3a2099c } diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 5fe8726af73eb5334f47046c93096341e987269b..574d8d311001ce15c2a2391caaec0a0b0b1653b5 100644 +index ed15f5c4a365a199d04e92d688035e4ab755e8db..f900c86697f5a3da45b724944a663fca8f89413e 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -735,6 +735,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -728,6 +728,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // Paper start - Prevent block entity and entity crashes final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); MinecraftServer.LOGGER.error(msg, throwable); @@ -103,10 +103,10 @@ index 5fe8726af73eb5334f47046c93096341e987269b..574d8d311001ce15c2a2391caaec0a0b // Paper end - Prevent block entity and entity crashes } diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 1fe93e01c5e37397aded5d1f99214bf1bffe70b7..400166ad0199dd4b96684904ef4748cdb72381bb 100644 +index 9389fd53f2bff0a9ca389694b312dc6da58befaf..da0ddb8285e157be0cc7b940a9590be5e3061e3d 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -296,6 +296,7 @@ public final class NaturalSpawner { +@@ -294,6 +294,7 @@ public final class NaturalSpawner { NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type)); } catch (Exception exception) { NaturalSpawner.LOGGER.warn("Failed to create mob", exception); @@ -114,7 +114,7 @@ index 1fe93e01c5e37397aded5d1f99214bf1bffe70b7..400166ad0199dd4b96684904ef4748cd } return null; -@@ -384,6 +385,7 @@ public final class NaturalSpawner { +@@ -382,6 +383,7 @@ public final class NaturalSpawner { entity = biomesettingsmobs_c.type.create(world.getLevel(), EntitySpawnReason.NATURAL); } catch (Exception exception) { NaturalSpawner.LOGGER.warn("Failed to create mob", exception); @@ -123,7 +123,7 @@ index 1fe93e01c5e37397aded5d1f99214bf1bffe70b7..400166ad0199dd4b96684904ef4748cd } diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index e1cd7497b1355030bf44b53aa30400604dff9aca..401f18deb9e9f019ea17ad684f2d5c4ea5e7ef97 100644 +index 79cf3089c128ef3c17d956da1e380670279ee5da..96ea7a5d5d4a69c83c2401e64750d41cd70088fc 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -496,8 +496,13 @@ public class LevelChunk extends ChunkAccess { @@ -142,7 +142,7 @@ index e1cd7497b1355030bf44b53aa30400604dff9aca..401f18deb9e9f019ea17ad684f2d5c4e } else { BlockState iblockdata1 = blockEntity.getBlockState(); -@@ -989,6 +994,7 @@ public class LevelChunk extends ChunkAccess { +@@ -986,6 +991,7 @@ public class LevelChunk extends ChunkAccess { // Paper start - Prevent block entity and entity crashes final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ()); net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable); @@ -171,10 +171,10 @@ index 15f273aa592828719de6e092d79a407dc8652dfe..b24e8255ab18eb5b2e4968aa62aa3d72 try { filechannel.close(); diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index 4c376f67ae311b4fedea27b3475f9fb56054aec2..22ddc74d85efb4e80e6f06acdf93341a122804fc 100644 +index 2c36d0796714997191c6540c34a9df60718065f6..0c0115ccd8541ac62975f4759b4e2083ac560332 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -416,20 +416,25 @@ public class CraftScheduler implements BukkitScheduler { +@@ -415,20 +415,25 @@ public class CraftScheduler implements BukkitScheduler { try { task.run(); } catch (final Throwable throwable) { diff --git a/patches/server/0063-Disable-Scoreboards-for-non-players-by-default.patch b/patches/server/0063-Disable-Scoreboards-for-non-players-by-default.patch index e5db1eccb0..3d53b13e30 100644 --- a/patches/server/0063-Disable-Scoreboards-for-non-players-by-default.patch +++ b/patches/server/0063-Disable-Scoreboards-for-non-players-by-default.patch @@ -23,10 +23,10 @@ index 49df5f4b09926556986e3a45d52ff299b878af76..8a61ca3cba2888e03e440519714705fe } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 6cc86412d45186dff312d9b1246fd1d03dbc15d8..b3f7d20c7853afaa396a90fbe23ed33d03fda8eb 100644 +index 6dba567e9f7a197af16598647f216b5323d1b601..47403887721914b632565947efae0dfa7c841588 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -873,6 +873,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -871,6 +871,7 @@ public abstract class LivingEntity extends Entity implements Attackable { String s = nbt.getString("Team"); Scoreboard scoreboard = this.level().getScoreboard(); PlayerTeam scoreboardteam = scoreboard.getPlayerTeam(s); diff --git a/patches/server/0067-Default-loading-permissions.yml-before-plugins.patch b/patches/server/0067-Default-loading-permissions.yml-before-plugins.patch index 8cf22bcec7..e933d73ae3 100644 --- a/patches/server/0067-Default-loading-permissions.yml-before-plugins.patch +++ b/patches/server/0067-Default-loading-permissions.yml-before-plugins.patch @@ -16,10 +16,10 @@ modify that. Under the previous logic, plugins were unable (cleanly) override pe A config option has been added for those who depend on the previous behavior, but I don't expect that. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index c80fe475edffce53363dfea658b9f13a2c6de1ca..bd18711474807518ceefa9d097d94a78b9e66158 100644 +index bb562ada45b828c79d83afdd1687edd32cbaf1dc..d581bfad059e60a693bc27285a723979e7d7dd34 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -491,6 +491,7 @@ public final class CraftServer implements Server { +@@ -490,6 +490,7 @@ public final class CraftServer implements Server { if (type == PluginLoadOrder.STARTUP) { this.helpMap.clear(); this.helpMap.initializeGeneralTopics(); @@ -27,7 +27,7 @@ index c80fe475edffce53363dfea658b9f13a2c6de1ca..bd18711474807518ceefa9d097d94a78 } Plugin[] plugins = this.pluginManager.getPlugins(); -@@ -510,7 +511,7 @@ public final class CraftServer implements Server { +@@ -509,7 +510,7 @@ public final class CraftServer implements Server { this.commandMap.registerServerAliases(); DefaultPermissions.registerCorePermissions(); CraftDefaultPermissions.registerCorePermissions(); diff --git a/patches/server/0068-Allow-Reloading-of-Custom-Permissions.patch b/patches/server/0068-Allow-Reloading-of-Custom-Permissions.patch index b7b06d1ab8..8205a118dd 100644 --- a/patches/server/0068-Allow-Reloading-of-Custom-Permissions.patch +++ b/patches/server/0068-Allow-Reloading-of-Custom-Permissions.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Allow Reloading of Custom Permissions https://github.com/PaperMC/Paper/issues/49 diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index bd18711474807518ceefa9d097d94a78b9e66158..2cc9faa6c560ceb8e50984e01a8f5caa042b62ba 100644 +index d581bfad059e60a693bc27285a723979e7d7dd34..2b4c1c3cc4b740d5aceb483c4066f23433c175d9 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2809,5 +2809,23 @@ public final class CraftServer implements Server { +@@ -2808,5 +2808,23 @@ public final class CraftServer implements Server { } return this.adventure$audiences; } diff --git a/patches/server/0069-Remove-Metadata-on-reload.patch b/patches/server/0069-Remove-Metadata-on-reload.patch index ec1a1512d4..e5592929ff 100644 --- a/patches/server/0069-Remove-Metadata-on-reload.patch +++ b/patches/server/0069-Remove-Metadata-on-reload.patch @@ -7,10 +7,10 @@ Metadata is not meant to persist reload as things break badly with non primitive This will remove metadata on reload so it does not crash everything if a plugin uses it. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 2cc9faa6c560ceb8e50984e01a8f5caa042b62ba..e9e612581683b27f35c0ef7adaae8e8b7eb677ec 100644 +index 2b4c1c3cc4b740d5aceb483c4066f23433c175d9..c6ea35f752c9a0bf9e5e07e3b501fd3fe8c30084 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1006,8 +1006,16 @@ public final class CraftServer implements Server { +@@ -1005,8 +1005,16 @@ public final class CraftServer implements Server { world.spigotConfig.init(); // Spigot } diff --git a/patches/server/0072-Add-World-Util-Methods.patch b/patches/server/0072-Add-World-Util-Methods.patch index 11bb708681..4c7b9c4d27 100644 --- a/patches/server/0072-Add-World-Util-Methods.patch +++ b/patches/server/0072-Add-World-Util-Methods.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Add World Util Methods Methods that can be used for other patches to help improve logic. diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 574d8d311001ce15c2a2391caaec0a0b0b1653b5..b37aeadf48e112170d64adc7587fdacbf6466aee 100644 +index f900c86697f5a3da45b724944a663fca8f89413e..d1b117f25bafb294f00c18be02be593061120956 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -341,6 +341,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -339,6 +339,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return chunk == null ? null : chunk.getFluidState(blockposition); } diff --git a/patches/server/0073-Custom-replacement-for-eaten-items.patch b/patches/server/0073-Custom-replacement-for-eaten-items.patch index 04ecd88925..25ce947852 100644 --- a/patches/server/0073-Custom-replacement-for-eaten-items.patch +++ b/patches/server/0073-Custom-replacement-for-eaten-items.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Custom replacement for eaten items diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index b3f7d20c7853afaa396a90fbe23ed33d03fda8eb..4fa5e7127549e090338b11e6493413a3fab254a0 100644 +index 47403887721914b632565947efae0dfa7c841588..031b7f51959d1b8ca30e4a9fda0a2832516c9c0c 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3984,10 +3984,11 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3982,10 +3982,11 @@ public abstract class LivingEntity extends Entity implements Attackable { if (!this.useItem.isEmpty() && this.isUsingItem()) { // CraftBukkit start - fire PlayerItemConsumeEvent ItemStack itemstack; @@ -21,7 +21,7 @@ index b3f7d20c7853afaa396a90fbe23ed33d03fda8eb..4fa5e7127549e090338b11e6493413a3 this.level().getCraftServer().getPluginManager().callEvent(event); if (event.isCancelled()) { -@@ -4005,6 +4006,12 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -4003,6 +4004,12 @@ public abstract class LivingEntity extends Entity implements Attackable { } else { itemstack = this.useItem.finishUsingItem(this.level(), this); } @@ -34,7 +34,7 @@ index b3f7d20c7853afaa396a90fbe23ed33d03fda8eb..4fa5e7127549e090338b11e6493413a3 // CraftBukkit end if (itemstack != this.useItem) { -@@ -4012,6 +4019,11 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -4010,6 +4017,11 @@ public abstract class LivingEntity extends Entity implements Attackable { } this.stopUsingItem(); diff --git a/patches/server/0074-handle-NaN-health-absorb-values-and-repair-bad-data.patch b/patches/server/0074-handle-NaN-health-absorb-values-and-repair-bad-data.patch index b46ff88f53..d019f5b8cb 100644 --- a/patches/server/0074-handle-NaN-health-absorb-values-and-repair-bad-data.patch +++ b/patches/server/0074-handle-NaN-health-absorb-values-and-repair-bad-data.patch @@ -5,10 +5,10 @@ Subject: [PATCH] handle NaN health/absorb values and repair bad data diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 4fa5e7127549e090338b11e6493413a3fab254a0..14d9e62c86309676ddd7eed19cce2f4b30a59b94 100644 +index 031b7f51959d1b8ca30e4a9fda0a2832516c9c0c..e5d1877f570b302f0b193e77ff5fdd7e89532513 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -833,7 +833,13 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -831,7 +831,13 @@ public abstract class LivingEntity extends Entity implements Attackable { @Override public void readAdditionalSaveData(CompoundTag nbt) { @@ -23,7 +23,7 @@ index 4fa5e7127549e090338b11e6493413a3fab254a0..14d9e62c86309676ddd7eed19cce2f4b if (nbt.contains("attributes", 9) && this.level() != null && !this.level().isClientSide) { this.getAttributes().load(nbt.getList("attributes", 10)); } -@@ -1373,6 +1379,10 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1371,6 +1377,10 @@ public abstract class LivingEntity extends Entity implements Attackable { } public void setHealth(float health) { @@ -34,7 +34,7 @@ index 4fa5e7127549e090338b11e6493413a3fab254a0..14d9e62c86309676ddd7eed19cce2f4b // CraftBukkit start - Handle scaled health if (this instanceof ServerPlayer) { org.bukkit.craftbukkit.entity.CraftPlayer player = ((ServerPlayer) this).getBukkitEntity(); -@@ -3841,7 +3851,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3839,7 +3849,7 @@ public abstract class LivingEntity extends Entity implements Attackable { } public final void setAbsorptionAmount(float absorptionAmount) { diff --git a/patches/server/0076-Configurable-spawn-chances-for-skeleton-horses.patch b/patches/server/0076-Configurable-spawn-chances-for-skeleton-horses.patch index 2a2c4f2b31..4cf4bf1181 100644 --- a/patches/server/0076-Configurable-spawn-chances-for-skeleton-horses.patch +++ b/patches/server/0076-Configurable-spawn-chances-for-skeleton-horses.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configurable spawn chances for skeleton horses diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 821df759e3410428b4558e22042c79f29238ebe2..b80af01529206bf55ed028dac41798f91da22f51 100644 +index 0e967e4c73dabc6cf6580d863c640cf4dff4f3bf..e623f8e75ec895d18d854a1f2c0dbe41a67dffc8 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -608,7 +608,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -594,7 +594,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (this.isRainingAt(blockposition)) { DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); diff --git a/patches/server/0077-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch b/patches/server/0077-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch index 58b312e58f..169cb0c090 100644 --- a/patches/server/0077-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch +++ b/patches/server/0077-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener Saves on some object allocation and processing when no plugin listens to this diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index d04ce36f79523417c7c2b49a8324b52ef6a6f0f4..412f97df192788bf38103a4c1754def47931fad4 100644 +index cc4c5fcbeca4862d8ff78b127cb3f2c07956dfaf..ece7f630937abd6d341a2498bac2f0afcfb1ce0f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1621,6 +1621,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { String s = String.valueOf(worldserver); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index b80af01529206bf55ed028dac41798f91da22f51..237a0b4dd0e1c437a021e1d2104e6d523b1f745a 100644 +index e623f8e75ec895d18d854a1f2c0dbe41a67dffc8..50296ff319fd6f97e27ec1cb6bdcd7b85a6ce926 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -230,6 +230,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -228,6 +228,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // CraftBukkit start public final LevelStorageSource.LevelStorageAccess convertable; public final UUID uuid; @@ -30,10 +30,10 @@ index b80af01529206bf55ed028dac41798f91da22f51..237a0b4dd0e1c437a021e1d2104e6d52 public LevelChunk getChunkIfLoaded(int x, int z) { return this.chunkSource.getChunk(x, z, false); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index b37aeadf48e112170d64adc7587fdacbf6466aee..9ad531912c4298658915b45b2870539059e8aadd 100644 +index d1b117f25bafb294f00c18be02be593061120956..9e88e9c473d1ab02344afd9634c625b95b5f38ef 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -491,7 +491,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -489,7 +489,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // CraftBukkit start iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam CraftWorld world = ((ServerLevel) this).getWorld(); diff --git a/patches/server/0078-Entity-AddTo-RemoveFrom-World-Events.patch b/patches/server/0078-Entity-AddTo-RemoveFrom-World-Events.patch index e529f629a6..2c0ae7a0fd 100644 --- a/patches/server/0078-Entity-AddTo-RemoveFrom-World-Events.patch +++ b/patches/server/0078-Entity-AddTo-RemoveFrom-World-Events.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Entity AddTo/RemoveFrom World Events diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 237a0b4dd0e1c437a021e1d2104e6d523b1f745a..6ec83b72bb9f762d606fcbf4b93c70f2b025f48f 100644 +index 50296ff319fd6f97e27ec1cb6bdcd7b85a6ce926..c36032803e8b7e4a8537f02738075e1a6baed3b1 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2224,6 +2224,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2194,6 +2194,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe entity.setOrigin(entity.getOriginVector().toLocation(getWorld())); } // Paper end - Entity origin API @@ -16,7 +16,7 @@ index 237a0b4dd0e1c437a021e1d2104e6d523b1f745a..6ec83b72bb9f762d606fcbf4b93c70f2 } public void onTrackingEnd(Entity entity) { -@@ -2294,6 +2295,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2264,6 +2265,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } // CraftBukkit end diff --git a/patches/server/0079-Configurable-Chunk-Inhabited-Time.patch b/patches/server/0079-Configurable-Chunk-Inhabited-Time.patch index 5a4d792994..d5d3a231fc 100644 --- a/patches/server/0079-Configurable-Chunk-Inhabited-Time.patch +++ b/patches/server/0079-Configurable-Chunk-Inhabited-Time.patch @@ -11,7 +11,7 @@ For people who want all chunks to be treated equally, you can chose a fixed valu This allows to fine-tune vanilla gameplay. diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 401f18deb9e9f019ea17ad684f2d5c4ea5e7ef97..add5ec0f8e8bd0b89511dcb656e1d4cda702a86b 100644 +index 96ea7a5d5d4a69c83c2401e64750d41cd70088fc..a1b6c13d496519ef6ce240036cec6642626903b9 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -195,6 +195,13 @@ public class LevelChunk extends ChunkAccess { diff --git a/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch b/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch index 4f7a58fe85..d895ad4117 100644 --- a/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch +++ b/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch @@ -28,10 +28,10 @@ index 1e9c68cd1868d083e6a790d56006dd4aa432010a..8a0ee9564fc36a2badf1357f7e6c47b5 + // Paper end - PlayerUseUnknownEntityEvent } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index ab31b31c61d652275a667f34ab018e4c8d0cdc08..33caf2d025a5770d2e3ebf044562314df6eb2c15 100644 +index 55d61a4c93233c0d3994e75f41e29065c2f1ea93..79db369b905744ab2fd69de1afc34feec589ec82 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2513,7 +2513,26 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2510,7 +2510,26 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl }); } } diff --git a/patches/server/0085-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch b/patches/server/0085-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch index f087a2a35f..6e252c8f8b 100644 --- a/patches/server/0085-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch +++ b/patches/server/0085-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix Cancelling BlockPlaceEvent triggering physics diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 6ec83b72bb9f762d606fcbf4b93c70f2b025f48f..5a9c703a252d0c1c57c23ef021e57cdd1de31585 100644 +index c36032803e8b7e4a8537f02738075e1a6baed3b1..828f47c6aadb609402f7237f8c234d595f39c970 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1402,11 +1402,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1372,11 +1372,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public void updateNeighborsAt(BlockPos pos, Block block) { diff --git a/patches/server/0088-Configurable-Player-Collision.patch b/patches/server/0088-Configurable-Player-Collision.patch index fe965dbf88..ef8bb51af9 100644 --- a/patches/server/0088-Configurable-Player-Collision.patch +++ b/patches/server/0088-Configurable-Player-Collision.patch @@ -18,10 +18,10 @@ index 9a1a961eabd4362c171da78c6be82c867f3696a4..1d0c473442b5c72245c356054440323e ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerPrefix); ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerSuffix); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 412f97df192788bf38103a4c1754def47931fad4..adab3f49722daa580dbb66012ab654a2a4a8084f 100644 +index ece7f630937abd6d341a2498bac2f0afcfb1ce0f..2e6531f39c6b65d79fc544459629ef61b2ad961a 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -655,6 +655,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop playersByName = new java.util.HashMap<>(); @@ -54,7 +54,7 @@ index 2af4b853fde493c1fa5c8d530aae4d68b79f7ba0..04e25dba87cc1531898bdf9640d6da44 public PlayerList(MinecraftServer server, LayeredRegistryAccess registryManager, PlayerDataStorage saveHandler, int maxPlayers) { this.cserver = server.server = new CraftServer((DedicatedServer) server, this); -@@ -349,6 +350,13 @@ public abstract class PlayerList { +@@ -348,6 +349,13 @@ public abstract class PlayerList { player.loadAndSpawnParentVehicle(optional); player.initInventoryMenu(); // CraftBukkit - Moved from above, added world @@ -68,7 +68,7 @@ index 2af4b853fde493c1fa5c8d530aae4d68b79f7ba0..04e25dba87cc1531898bdf9640d6da44 PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); } -@@ -471,6 +479,16 @@ public abstract class PlayerList { +@@ -470,6 +478,16 @@ public abstract class PlayerList { entityplayer.doTick(); // SPIGOT-924 // CraftBukkit end @@ -85,7 +85,7 @@ index 2af4b853fde493c1fa5c8d530aae4d68b79f7ba0..04e25dba87cc1531898bdf9640d6da44 this.save(entityplayer); if (entityplayer.isPassenger()) { Entity entity = entityplayer.getRootVehicle(); -@@ -1098,6 +1116,13 @@ public abstract class PlayerList { +@@ -1096,6 +1114,13 @@ public abstract class PlayerList { } // CraftBukkit end diff --git a/patches/server/0091-EntityRegainHealthEvent-isFastRegen-API.patch b/patches/server/0091-EntityRegainHealthEvent-isFastRegen-API.patch index b9219fec57..c6c6929c40 100644 --- a/patches/server/0091-EntityRegainHealthEvent-isFastRegen-API.patch +++ b/patches/server/0091-EntityRegainHealthEvent-isFastRegen-API.patch @@ -6,10 +6,10 @@ Subject: [PATCH] EntityRegainHealthEvent isFastRegen API Don't even get me started diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 14d9e62c86309676ddd7eed19cce2f4b30a59b94..6ea3488a578a7464bd34df265742a777575c9029 100644 +index e5d1877f570b302f0b193e77ff5fdd7e89532513..4a6f9a8b7db8d0e1c3cca5a0a4856d38cb38b94e 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1352,10 +1352,16 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1350,10 +1350,16 @@ public abstract class LivingEntity extends Entity implements Attackable { } public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) { diff --git a/patches/server/0093-remove-null-possibility-for-getServer-singleton.patch b/patches/server/0093-remove-null-possibility-for-getServer-singleton.patch index bc56cf8017..3ebd34b206 100644 --- a/patches/server/0093-remove-null-possibility-for-getServer-singleton.patch +++ b/patches/server/0093-remove-null-possibility-for-getServer-singleton.patch @@ -6,10 +6,10 @@ Subject: [PATCH] remove null possibility for getServer singleton to stop IDE complaining about potential NPE diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index adab3f49722daa580dbb66012ab654a2a4a8084f..55d376d4ddc522cc1a9841471514aa077ebfaac9 100644 +index 2e6531f39c6b65d79fc544459629ef61b2ad961a..bdc4eafcad57bb0073662e904bde87e9ac5ed0f3 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -204,6 +204,7 @@ import co.aikar.timings.MinecraftTimings; // Paper +@@ -203,6 +203,7 @@ import org.bukkit.event.server.ServerLoadEvent; public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource { @@ -17,7 +17,7 @@ index adab3f49722daa580dbb66012ab654a2a4a8084f..55d376d4ddc522cc1a9841471514aa07 public static final Logger LOGGER = LogUtils.getLogger(); public static final net.kyori.adventure.text.logger.slf4j.ComponentLogger COMPONENT_LOGGER = net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(LOGGER.getName()); // Paper public static final String VANILLA_BRAND = "vanilla"; -@@ -341,6 +342,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { this.stopRecordingMetrics(); -@@ -2625,9 +2627,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions diff --git a/patches/server/0101-Fix-global-sound-handling.patch b/patches/server/0101-Fix-global-sound-handling.patch index 1c4cad79e3..8af9a82dea 100644 --- a/patches/server/0101-Fix-global-sound-handling.patch +++ b/patches/server/0101-Fix-global-sound-handling.patch @@ -11,10 +11,10 @@ Co-authored-by: lexikiq Co-authored-by: Aikar diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 5a9c703a252d0c1c57c23ef021e57cdd1de31585..022ec2ff1c5a6a1de867b2a6dafb339d55a0905d 100644 +index 828f47c6aadb609402f7237f8c234d595f39c970..88c93a2e67c8d1bc227c7fa35bb919a40009f931 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1335,7 +1335,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1305,7 +1305,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public void levelEvent(@Nullable Player player, int eventId, BlockPos pos, int data) { @@ -23,7 +23,7 @@ index 5a9c703a252d0c1c57c23ef021e57cdd1de31585..022ec2ff1c5a6a1de867b2a6dafb339d } public int getLogicalHeight() { -@@ -2152,6 +2152,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2122,6 +2122,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe return this.serverLevelData.getGameRules(); } diff --git a/patches/server/0104-Add-setting-for-proxy-online-mode-status.patch b/patches/server/0104-Add-setting-for-proxy-online-mode-status.patch index 8158eb6cc7..58541b2ca3 100644 --- a/patches/server/0104-Add-setting-for-proxy-online-mode-status.patch +++ b/patches/server/0104-Add-setting-for-proxy-online-mode-status.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Add setting for proxy online mode status TODO: Add isProxyOnlineMode check to Metrics diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 07969f82a3df1b71bee275a99ef9170a4f9bbbb0..a5880be1ec88c70f7ee46225036b04dac87943d4 100644 +index 5d9772a6c35e8f849e8879f510b2c586b148074c..7c2b2dbc03bf4c3308a3e2a34260fee56d646488 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -575,7 +575,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -571,7 +571,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface public boolean enforceSecureProfile() { DedicatedServerProperties dedicatedserverproperties = this.getProperties(); @@ -60,10 +60,10 @@ index a0b0614ac7d2009db5c6c10ab4a5f09dd447c635..653856d0b8dcf2baf4cc77a276f17c8c } else { String[] astring1 = astring; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index e9e612581683b27f35c0ef7adaae8e8b7eb677ec..e04c3f623a316ac3a7b3700cfd5165e799bc0afc 100644 +index c6ea35f752c9a0bf9e5e07e3b501fd3fe8c30084..f970f821f5ac8cbad90ebb8dd8e8bf222ae229ae 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1892,7 +1892,7 @@ public final class CraftServer implements Server { +@@ -1891,7 +1891,7 @@ public final class CraftServer implements Server { if (result == null) { GameProfile profile = null; // Only fetch an online UUID in online mode diff --git a/patches/server/0106-Configurable-packet-in-spam-threshold.patch b/patches/server/0106-Configurable-packet-in-spam-threshold.patch index 3a0784210e..b28e858037 100644 --- a/patches/server/0106-Configurable-packet-in-spam-threshold.patch +++ b/patches/server/0106-Configurable-packet-in-spam-threshold.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configurable packet in spam threshold diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 33caf2d025a5770d2e3ebf044562314df6eb2c15..d5952a0ea86a562cb7ff2e9597260ed9c8ad7192 100644 +index 79db369b905744ab2fd69de1afc34feec589ec82..be690a8a22c126b007e623c8fe627bab00a28bad 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1545,13 +1545,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0107-Configurable-flying-kick-messages.patch b/patches/server/0107-Configurable-flying-kick-messages.patch index 1c746539c1..00bd532614 100644 --- a/patches/server/0107-Configurable-flying-kick-messages.patch +++ b/patches/server/0107-Configurable-flying-kick-messages.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configurable flying kick messages diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index d5952a0ea86a562cb7ff2e9597260ed9c8ad7192..d02c743c8a4fe5d640df53dda881e1d1cba05f5f 100644 +index be690a8a22c126b007e623c8fe627bab00a28bad..bc0d7bfb01a613c8fa567238f973f834cf3e3f17 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -355,7 +355,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0111-Allow-Reloading-of-Command-Aliases.patch b/patches/server/0111-Allow-Reloading-of-Command-Aliases.patch index a4e93d3f78..aa356f414e 100644 --- a/patches/server/0111-Allow-Reloading-of-Command-Aliases.patch +++ b/patches/server/0111-Allow-Reloading-of-Command-Aliases.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Allow Reloading of Command Aliases Reload the aliases stored in commands.yml diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index e04c3f623a316ac3a7b3700cfd5165e799bc0afc..1f028c40dbe159f836e255ec52287903bca9fab8 100644 +index f970f821f5ac8cbad90ebb8dd8e8bf222ae229ae..c36bba560d5b17c69c2034cd1fcd711234c13414 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2835,5 +2835,24 @@ public final class CraftServer implements Server { +@@ -2834,5 +2834,24 @@ public final class CraftServer implements Server { DefaultPermissions.registerCorePermissions(); CraftDefaultPermissions.registerCorePermissions(); } diff --git a/patches/server/0115-Optimize-Level.hasChunkAt-BlockPosition-Z.patch b/patches/server/0115-Optimize-Level.hasChunkAt-BlockPosition-Z.patch index 2fc9b6d341..526301e39d 100644 --- a/patches/server/0115-Optimize-Level.hasChunkAt-BlockPosition-Z.patch +++ b/patches/server/0115-Optimize-Level.hasChunkAt-BlockPosition-Z.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Optimize Level.hasChunkAt(BlockPosition)Z Reduce method invocations for World.isLoaded(BlockPosition)Z diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 529b6eccb634f1f4677118c48e174b42eead2c0b..658ceb9c43bb48f88596cd7270e276a369a3937e 100644 +index 675dcb6eb5c33f6ec582ff20118d2f73745914a9..943c14b26cf5b1c9f9ea1acec058cecac3b93bf7 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -342,6 +342,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -340,6 +340,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return chunk == null ? null : chunk.getFluidState(blockposition); } diff --git a/patches/server/0123-Provide-E-TE-Chunk-count-stat-methods.patch b/patches/server/0123-Provide-E-TE-Chunk-count-stat-methods.patch index ad688961b8..96ee3335c0 100644 --- a/patches/server/0123-Provide-E-TE-Chunk-count-stat-methods.patch +++ b/patches/server/0123-Provide-E-TE-Chunk-count-stat-methods.patch @@ -7,7 +7,7 @@ Provides counts without the ineffeciency of using .getEntities().size() which creates copy of the collections. diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 658ceb9c43bb48f88596cd7270e276a369a3937e..b34663ba24a0925c7fe65b354f4029c51ecc3bd1 100644 +index 943c14b26cf5b1c9f9ea1acec058cecac3b93bf7..e5eac1977f77b7ce1112bfe7ac1b77d9ef4d90f4 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -116,7 +116,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { diff --git a/patches/server/0124-Enforce-Sync-Player-Saves.patch b/patches/server/0124-Enforce-Sync-Player-Saves.patch index 7278b20368..bbf020dcb3 100644 --- a/patches/server/0124-Enforce-Sync-Player-Saves.patch +++ b/patches/server/0124-Enforce-Sync-Player-Saves.patch @@ -7,20 +7,18 @@ Saving players async is extremely dangerous. This will force it to main the same way we handle async chunk loads. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 04e25dba87cc1531898bdf9640d6da44ee3bf410..18d4ee1e1fb37848ac6587a0a68785be1851b1e8 100644 +index d0d2b687ec851e3fa08864897774897a1fcd7df8..f9ffae36beb13db416432068d8ee00de21d0c1fe 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -998,11 +998,13 @@ public abstract class PlayerList { +@@ -997,10 +997,12 @@ public abstract class PlayerList { } public void saveAll() { + io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main - MinecraftTimings.savePlayers.startTiming(); // Paper for (int i = 0; i < this.players.size(); ++i) { -- this.save((ServerPlayer) this.players.get(i)); -+ this.save(this.players.get(i)); + this.save((ServerPlayer) this.players.get(i)); } - MinecraftTimings.savePlayers.stopTiming(); // Paper + + return null; }); // Paper - ensure main } diff --git a/patches/server/0125-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch b/patches/server/0125-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch index 6f2899e0db..122c225e01 100644 --- a/patches/server/0125-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch +++ b/patches/server/0125-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch @@ -127,10 +127,10 @@ index 7f3ac3e8631e30c968ef664f994ad208d05eb4a3..b9160ebca0d11dbbf96da5f0f5810d30 @Override diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 6ea3488a578a7464bd34df265742a777575c9029..237025be183b3cc93920430075edcc0bb2899b68 100644 +index 4a6f9a8b7db8d0e1c3cca5a0a4856d38cb38b94e..7a648a8c3f25397e1c883a42648b21a05901513f 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1837,7 +1837,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1835,7 +1835,7 @@ public abstract class LivingEntity extends Entity implements Attackable { protected void dropExperience(ServerLevel world, @Nullable Entity attacker) { // CraftBukkit start - Update getExpReward() above if the removed if() changes! if (!(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time @@ -285,10 +285,10 @@ index 56d8ed71861b0a47692fde4c5acc97aaba8166da..13bc52bc856031c930370828b0381e43 world.levelEvent(1042, blockposition, 0); diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 3cefda12d4c2ca2c4e9ef97eff961a55af164d6b..43c2b411115d3a8a0e47d3e2277789b2667897af 100644 +index 27cbec37c6ea278232970ae035795fdecca71735..f1711f774f844024ca7b678385daaace6cda9f46 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -363,8 +363,13 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -354,8 +354,13 @@ public class Block extends BlockBehaviour implements ItemLike { } public void popExperience(ServerLevel world, BlockPos pos, int size) { diff --git a/patches/server/0126-Cap-Entity-Collisions.patch b/patches/server/0126-Cap-Entity-Collisions.patch index c5acd9fe9a..0a1d097e37 100644 --- a/patches/server/0126-Cap-Entity-Collisions.patch +++ b/patches/server/0126-Cap-Entity-Collisions.patch @@ -24,10 +24,10 @@ index 847fd720f11e89d906430c820bc92afe0454761d..b1b26e7c0f66f0697bcfe9eb045d45f3 @javax.annotation.Nullable private org.bukkit.util.Vector origin; diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 237025be183b3cc93920430075edcc0bb2899b68..f2f8fbc8a8cf32bcba0ad7ac9b6cdd75468e062a 100644 +index 7a648a8c3f25397e1c883a42648b21a05901513f..bcc0137fec45406e70231b4e2a5bd69dc08ffb5a 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3642,10 +3642,12 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3640,10 +3640,12 @@ public abstract class LivingEntity extends Entity implements Attackable { } Iterator iterator1 = list.iterator(); diff --git a/patches/server/0127-Remove-CraftScheduler-Async-Task-Debugger.patch b/patches/server/0127-Remove-CraftScheduler-Async-Task-Debugger.patch index 8c7d283f77..15ad3dc3e2 100644 --- a/patches/server/0127-Remove-CraftScheduler-Async-Task-Debugger.patch +++ b/patches/server/0127-Remove-CraftScheduler-Async-Task-Debugger.patch @@ -9,10 +9,10 @@ One report of a suspected memory leak with the system. This adds additional overhead to asynchronous task dispatching diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index 22ddc74d85efb4e80e6f06acdf93341a122804fc..0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6 100644 +index 0c0115ccd8541ac62975f4759b4e2083ac560332..300d31e31a55dbee3489320e21e42f14ac429478 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -433,7 +433,7 @@ public class CraftScheduler implements BukkitScheduler { +@@ -432,7 +432,7 @@ public class CraftScheduler implements BukkitScheduler { } this.parsePending(); } else { @@ -21,16 +21,16 @@ index 22ddc74d85efb4e80e6f06acdf93341a122804fc..0e7f402a7b841c5f6f5a4b699b7bb3d9 this.executor.execute(new com.destroystokyo.paper.ServerSchedulerReportingWrapper(task)); // Paper // We don't need to parse pending // (async tasks must live with race-conditions if they attempt to cancel between these few lines of code) -@@ -450,7 +450,7 @@ public class CraftScheduler implements BukkitScheduler { +@@ -447,7 +447,7 @@ public class CraftScheduler implements BukkitScheduler { + } this.pending.addAll(temp); temp.clear(); - MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming(); // Paper - this.debugHead = this.debugHead.getNextHead(this.currentTick); + //this.debugHead = this.debugHead.getNextHead(this.currentTick); // Paper } private void addTask(final CraftTask task) { -@@ -514,10 +514,15 @@ public class CraftScheduler implements BukkitScheduler { +@@ -509,10 +509,15 @@ public class CraftScheduler implements BukkitScheduler { @Override public String toString() { diff --git a/patches/server/0128-Properly-handle-async-calls-to-restart-the-server.patch b/patches/server/0128-Properly-handle-async-calls-to-restart-the-server.patch index f34ed462be..2c9eb1dd3c 100644 --- a/patches/server/0128-Properly-handle-async-calls-to-restart-the-server.patch +++ b/patches/server/0128-Properly-handle-async-calls-to-restart-the-server.patch @@ -30,10 +30,10 @@ will have plugins and worlds saving to the disk has a high potential to result in corruption/dataloss. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index d32f0edc31f099f53656fe56dafb98903f132502..5e9b85a46708cfe297533f13255629d72cd09c73 100644 +index 383808406dd3a6c5b6098db93e638749489b80e3..0adba72139779a20eed8f489f7cfaff9e84e24f4 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -248,6 +248,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, ServerLevel> levels; private PlayerList playerList; private volatile boolean running; @@ -41,7 +41,7 @@ index d32f0edc31f099f53656fe56dafb98903f132502..5e9b85a46708cfe297533f13255629d7 private boolean stopped; private int tickCount; private int ticksUntilAutosave; -@@ -953,7 +954,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop capturedTileEntities = new HashMap<>(); public List captureDrops; public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); -@@ -384,7 +384,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -382,7 +382,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { // CraftBukkit start - tree generation if (this.captureTreeGeneration) { @@ -39,7 +39,7 @@ index 106f4dd7f49d3b81a9bc08cd034cccac90042f84..c628524274110bcad175472dbcb82e6c if (blockstate == null) { blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags); this.capturedBlockStates.put(pos.immutable(), blockstate); -@@ -405,7 +405,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -403,7 +403,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // CraftBukkit start - capture blockstates boolean captured = false; if (this.captureBlockStates && !this.capturedBlockStates.containsKey(pos)) { @@ -49,7 +49,7 @@ index 106f4dd7f49d3b81a9bc08cd034cccac90042f84..c628524274110bcad175472dbcb82e6c this.capturedBlockStates.put(pos.immutable(), blockstate); captured = true; } -@@ -608,7 +609,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -606,7 +607,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public BlockState getBlockState(BlockPos pos) { // CraftBukkit start - tree generation if (this.captureTreeGeneration) { diff --git a/patches/server/0160-API-to-get-a-BlockState-without-a-snapshot.patch b/patches/server/0160-API-to-get-a-BlockState-without-a-snapshot.patch index 3b12a52009..97e12295c9 100644 --- a/patches/server/0160-API-to-get-a-BlockState-without-a-snapshot.patch +++ b/patches/server/0160-API-to-get-a-BlockState-without-a-snapshot.patch @@ -13,10 +13,10 @@ also Avoid NPE during CraftBlockEntityState load if could not get TE If Tile Entity was null, correct Sign to return empty lines instead of null diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 4536632687e71b02d5945cac3816b72ac540935e..46a831f86b512f4228be8ccee40fb0f7bf0d6df6 100644 +index 3d7c5db5514f9d4401da22d2df88c5614051e568..50413d317ce0282752c57535637f87d529f4c09f 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -59,6 +59,7 @@ public abstract class BlockEntity { +@@ -54,6 +54,7 @@ public abstract class BlockEntity { this.worldPosition = pos.immutable(); this.validateBlockState(state); this.blockState = state; @@ -24,7 +24,7 @@ index 4536632687e71b02d5945cac3816b72ac540935e..46a831f86b512f4228be8ccee40fb0f7 } private void validateBlockState(BlockState state) { -@@ -92,7 +93,7 @@ public abstract class BlockEntity { +@@ -87,7 +88,7 @@ public abstract class BlockEntity { // CraftBukkit start - read container protected void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) { @@ -33,7 +33,7 @@ index 4536632687e71b02d5945cac3816b72ac540935e..46a831f86b512f4228be8ccee40fb0f7 net.minecraft.nbt.Tag persistentDataTag = nbt.get("PublicBukkitValues"); if (persistentDataTag instanceof CompoundTag) { -@@ -380,8 +381,15 @@ public abstract class BlockEntity { +@@ -375,8 +376,15 @@ public abstract class BlockEntity { // CraftBukkit start - add method public InventoryHolder getOwner() { diff --git a/patches/server/0161-AsyncTabCompleteEvent.patch b/patches/server/0161-AsyncTabCompleteEvent.patch index 8bf913b966..2436de2911 100644 --- a/patches/server/0161-AsyncTabCompleteEvent.patch +++ b/patches/server/0161-AsyncTabCompleteEvent.patch @@ -16,7 +16,7 @@ Also adds isCommand and getLocation to the sync TabCompleteEvent Co-authored-by: Aikar diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 1140eac4bb9443508df61e7a50d54add4b206654..752460c4650bebb2860bea82ca186a0f97b1692b 100644 +index 414077a1fed2955bd64ac7091af1daeda2a92e2c..79d9a58c66382fd94ab5f6020285e341b0114f6a 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -722,21 +722,58 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @@ -80,10 +80,10 @@ index 1140eac4bb9443508df61e7a50d54add4b206654..752460c4650bebb2860bea82ca186a0f this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index fa6284ebe3bdbf97b40a2ab61ba94062cdcf045e..367ecbb023ddfbadb92aa4351ff601a3ed58a358 100644 +index 2d1f92f75e83aacd39440d2619befdf6cd545af4..1dd440057cb1d8acce7bfaa7ab1814937a4c63af 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2298,7 +2298,7 @@ public final class CraftServer implements Server { +@@ -2297,7 +2297,7 @@ public final class CraftServer implements Server { offers = this.tabCompleteChat(player, message); } diff --git a/patches/server/0164-PlayerNaturallySpawnCreaturesEvent.patch b/patches/server/0164-PlayerNaturallySpawnCreaturesEvent.patch index 176e327764..f61ad3434c 100644 --- a/patches/server/0164-PlayerNaturallySpawnCreaturesEvent.patch +++ b/patches/server/0164-PlayerNaturallySpawnCreaturesEvent.patch @@ -9,10 +9,10 @@ from triggering monster spawns on a server. Also a highly more effecient way to blanket block spawns in a world diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 30b28d9523820ed138c837ab9ee9bbb23c0dd285..01c32ed14b1047671883911f8606ef2924ebee73 100644 +index 3bb6eaabe8f62b556a52b83227b48f8324a9d0f0..b8aff86c8533ea92b0244ea85ed786073c4053a8 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1100,7 +1100,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1098,7 +1098,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider chunkRange = (chunkRange > this.level.spigotConfig.viewDistance) ? (byte) this.level.spigotConfig.viewDistance : chunkRange; chunkRange = (chunkRange > 8) ? 8 : chunkRange; @@ -23,7 +23,7 @@ index 30b28d9523820ed138c837ab9ee9bbb23c0dd285..01c32ed14b1047671883911f8606ef29 // Spigot end Iterator iterator = this.playerMap.getAllPlayers().iterator(); -@@ -1112,6 +1114,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1110,6 +1112,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } entityplayer = (ServerPlayer) iterator.next(); @@ -40,10 +40,10 @@ index 30b28d9523820ed138c837ab9ee9bbb23c0dd285..01c32ed14b1047671883911f8606ef29 return true; diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 93422468474189343cdc1e29f06f6dfb12e4760a..fef86453d5cf0fe0f11a2a061169cd301b777434 100644 +index ccb6f28689a3cf7da4ea323c5dd8f595036c4b43..d4eb7608a3e40d2da4c427e9b3a2ce916be86df1 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -520,6 +520,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -504,6 +504,15 @@ public class ServerChunkCache extends ChunkSource { List list1; if (flag && (this.spawnEnemies || this.spawnFriendlies)) { diff --git a/patches/server/0166-PreCreatureSpawnEvent.patch b/patches/server/0166-PreCreatureSpawnEvent.patch index 8c22573ffb..0f7306bfc5 100644 --- a/patches/server/0166-PreCreatureSpawnEvent.patch +++ b/patches/server/0166-PreCreatureSpawnEvent.patch @@ -55,10 +55,10 @@ index e139ed6bc6f2dd07fe546588b31309ba30ed9755..34c3bf85473b3ad89355ebc21b68c59b if (t0 != null) { diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 970161efa46b3a71ddae665f9df5966c70fd3471..5fe268b5c3297de7650f5d1f310cdf8ac231de75 100644 +index 17ab230c95901f0533997ac117d5b3d852fcd467..8f4ec4f0ea7ff2f9a952120785aea65f6559f897 100644 --- a/src/main/java/net/minecraft/world/entity/EntityType.java +++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -506,6 +506,16 @@ public class EntityType implements FeatureElement, EntityTypeT +@@ -497,6 +497,16 @@ public class EntityType implements FeatureElement, EntityTypeT @Nullable public T spawn(ServerLevel worldserver, @Nullable Consumer consumer, BlockPos blockposition, EntitySpawnReason entityspawnreason, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { // CraftBukkit end @@ -114,10 +114,10 @@ index 6c29e55239fdcf8df3b9dc012aa80cebcd3a837a..bb3f3bec350dda43dbf5eda0a8c8057a Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, EntitySpawnReason.SPAWNER, (entity1) -> { entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot()); diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 400166ad0199dd4b96684904ef4748cdb72381bb..0b41149ae134084cef4016241ce923dac0349846 100644 +index da0ddb8285e157be0cc7b940a9590be5e3061e3d..5a0ea71dc39c582ef6c843dc0532adb04ba120ce 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -230,7 +230,13 @@ public final class NaturalSpawner { +@@ -228,7 +228,13 @@ public final class NaturalSpawner { j1 = biomesettingsmobs_c.minCount + world.random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount); } @@ -132,7 +132,7 @@ index 400166ad0199dd4b96684904ef4748cdb72381bb..0b41149ae134084cef4016241ce923da Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type); if (entityinsentient == null) { -@@ -278,10 +284,31 @@ public final class NaturalSpawner { +@@ -276,10 +282,31 @@ public final class NaturalSpawner { return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isNaturalSpawningAllowed((BlockPos) pos)); } diff --git a/patches/server/0174-Implement-extended-PaperServerListPingEvent.patch b/patches/server/0174-Implement-extended-PaperServerListPingEvent.patch index caa788dc53..e0dbee4fe8 100644 --- a/patches/server/0174-Implement-extended-PaperServerListPingEvent.patch +++ b/patches/server/0174-Implement-extended-PaperServerListPingEvent.patch @@ -170,7 +170,7 @@ index 0000000000000000000000000000000000000000..30a19d10869f73d67b794e8e4c035bc5 + +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 5e9b85a46708cfe297533f13255629d72cd09c73..fe981e45b3b61f24da3e137c68312e98977dad73 100644 +index 0adba72139779a20eed8f489f7cfaff9e84e24f4..260d755666efc94e2ea2c8fdb38d7deddda82c08 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -3,6 +3,9 @@ package net.minecraft.server; @@ -183,7 +183,7 @@ index 5e9b85a46708cfe297533f13255629d72cd09c73..fe981e45b3b61f24da3e137c68312e98 import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -@@ -1592,7 +1595,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop() { @Override public int compare(final CraftTask o1, final CraftTask o2) { -@@ -93,12 +93,13 @@ public class CraftScheduler implements BukkitScheduler { +@@ -92,12 +92,13 @@ public class CraftScheduler implements BukkitScheduler { /** * These are tasks that are currently active. It's provided for 'viewing' the current state. */ @@ -187,7 +187,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 private final Executor executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %d").build()); private CraftAsyncDebugger debugHead = new CraftAsyncDebugger(-1, null, null) { @Override -@@ -107,12 +108,31 @@ public class CraftScheduler implements BukkitScheduler { +@@ -106,12 +107,31 @@ public class CraftScheduler implements BukkitScheduler { } }; private CraftAsyncDebugger debugTail = this.debugHead; @@ -219,7 +219,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 @Override public int scheduleSyncDelayedTask(final Plugin plugin, final Runnable task) { return this.scheduleSyncDelayedTask(plugin, task, 0L); -@@ -229,7 +249,7 @@ public class CraftScheduler implements BukkitScheduler { +@@ -228,7 +248,7 @@ public class CraftScheduler implements BukkitScheduler { } else if (period < CraftTask.NO_REPEATING) { period = CraftTask.NO_REPEATING; } @@ -228,7 +228,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 } @Override -@@ -245,6 +265,11 @@ public class CraftScheduler implements BukkitScheduler { +@@ -244,6 +264,11 @@ public class CraftScheduler implements BukkitScheduler { if (taskId <= 0) { return; } @@ -240,7 +240,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 CraftTask task = this.runners.get(taskId); if (task != null) { task.cancel0(); -@@ -287,6 +312,11 @@ public class CraftScheduler implements BukkitScheduler { +@@ -286,6 +311,11 @@ public class CraftScheduler implements BukkitScheduler { @Override public void cancelTasks(final Plugin plugin) { Preconditions.checkArgument(plugin != null, "Cannot cancel tasks of null plugin"); @@ -252,7 +252,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 final CraftTask task = new CraftTask( new Runnable() { @Override -@@ -326,6 +356,13 @@ public class CraftScheduler implements BukkitScheduler { +@@ -325,6 +355,13 @@ public class CraftScheduler implements BukkitScheduler { @Override public boolean isCurrentlyRunning(final int taskId) { @@ -266,7 +266,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 final CraftTask task = this.runners.get(taskId); if (task == null) { return false; -@@ -344,6 +381,11 @@ public class CraftScheduler implements BukkitScheduler { +@@ -343,6 +380,11 @@ public class CraftScheduler implements BukkitScheduler { if (taskId <= 0) { return false; } @@ -278,7 +278,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 for (CraftTask task = this.head.getNext(); task != null; task = task.getNext()) { if (task.getTaskId() == taskId) { return task.getPeriod() >= CraftTask.NO_REPEATING; // The task will run -@@ -355,6 +397,12 @@ public class CraftScheduler implements BukkitScheduler { +@@ -354,6 +396,12 @@ public class CraftScheduler implements BukkitScheduler { @Override public List getActiveWorkers() { @@ -291,7 +291,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 final ArrayList workers = new ArrayList(); for (final CraftTask taskObj : this.runners.values()) { // Iterator will be a best-effort (may fail to grab very new values) if called from an async thread -@@ -392,6 +440,11 @@ public class CraftScheduler implements BukkitScheduler { +@@ -391,6 +439,11 @@ public class CraftScheduler implements BukkitScheduler { pending.add(task); } } @@ -303,7 +303,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 return pending; } -@@ -400,6 +453,11 @@ public class CraftScheduler implements BukkitScheduler { +@@ -399,6 +452,11 @@ public class CraftScheduler implements BukkitScheduler { */ public void mainThreadHeartbeat() { this.currentTick++; @@ -315,7 +315,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 final List temp = this.temp; this.parsePending(); while (this.isReady(this.currentTick)) { -@@ -434,7 +492,7 @@ public class CraftScheduler implements BukkitScheduler { +@@ -433,7 +491,7 @@ public class CraftScheduler implements BukkitScheduler { this.parsePending(); } else { // this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(this.currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper @@ -324,7 +324,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 // We don't need to parse pending // (async tasks must live with race-conditions if they attempt to cancel between these few lines of code) } -@@ -453,7 +511,7 @@ public class CraftScheduler implements BukkitScheduler { +@@ -450,7 +508,7 @@ public class CraftScheduler implements BukkitScheduler { //this.debugHead = this.debugHead.getNextHead(this.currentTick); // Paper } @@ -333,7 +333,7 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 final AtomicReference tail = this.tail; CraftTask tailTask = tail.get(); while (!tail.compareAndSet(tailTask, task)) { -@@ -462,7 +520,13 @@ public class CraftScheduler implements BukkitScheduler { +@@ -459,7 +517,13 @@ public class CraftScheduler implements BukkitScheduler { tailTask.setNext(task); } @@ -348,23 +348,12 @@ index 0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6..fd5a058dd802599598a64467cf25f083 task.setNextRun(this.currentTick + delay); this.addTask(task); return task; -@@ -485,8 +549,8 @@ public class CraftScheduler implements BukkitScheduler { +@@ -482,7 +546,7 @@ public class CraftScheduler implements BukkitScheduler { return id; } - private void parsePending() { -- MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); + void parsePending() { // Paper -+ if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); // Paper CraftTask head = this.head; CraftTask task = head.getNext(); CraftTask lastTask = head; -@@ -505,7 +569,7 @@ public class CraftScheduler implements BukkitScheduler { - task.setNext(null); - } - this.head = lastTask; -- MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); -+ if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); // Paper - } - - private boolean isReady(final int currentTick) { diff --git a/patches/server/0186-Expand-World.spawnParticle-API-and-add-Builder.patch b/patches/server/0186-Expand-World.spawnParticle-API-and-add-Builder.patch index 8fcc3562f2..da14ccdaa5 100644 --- a/patches/server/0186-Expand-World.spawnParticle-API-and-add-Builder.patch +++ b/patches/server/0186-Expand-World.spawnParticle-API-and-add-Builder.patch @@ -10,10 +10,10 @@ Adds an option to control the force mode of the particle. This adds a new Builder API which is much friendlier to use. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 022ec2ff1c5a6a1de867b2a6dafb339d55a0905d..17cb827bc90d980d73719776fca967a1d307ce0a 100644 +index 88c93a2e67c8d1bc227c7fa35bb919a40009f931..0c0d19708832a49734ea08ae05696e0cb20616e4 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1566,12 +1566,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1536,12 +1536,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } public int sendParticles(ServerPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) { diff --git a/patches/server/0198-Make-shield-blocking-delay-configurable.patch b/patches/server/0198-Make-shield-blocking-delay-configurable.patch index 8bd30c1391..0c056446f0 100644 --- a/patches/server/0198-Make-shield-blocking-delay-configurable.patch +++ b/patches/server/0198-Make-shield-blocking-delay-configurable.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Make shield blocking delay configurable diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 76b71af07a311bc415b36f517afab31505a14483..0a4d2abc5b70c5e4e93dc06fe112e2398d9916e7 100644 +index 84e11e2c62e643f959f1a570a27f6ad07df165d4..08a2fbca50e26938e46e49dae7b101cfc375b02e 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4103,12 +4103,24 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -4101,12 +4101,24 @@ public abstract class LivingEntity extends Entity implements Attackable { if (this.isUsingItem() && !this.useItem.isEmpty()) { Item item = this.useItem.getItem(); diff --git a/patches/server/0201-Add-entity-knockback-events.patch b/patches/server/0201-Add-entity-knockback-events.patch index c41689a196..8615d22e3d 100644 --- a/patches/server/0201-Add-entity-knockback-events.patch +++ b/patches/server/0201-Add-entity-knockback-events.patch @@ -38,10 +38,10 @@ index 087f030985180b91a809fb45244e23106da62e34..011006bc2e88a9fec98796f939c07d88 } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 0a4d2abc5b70c5e4e93dc06fe112e2398d9916e7..c9d7589a18e9cee204f4e52368a60aa421c1e150 100644 +index 08a2fbca50e26938e46e49dae7b101cfc375b02e..cfff596d720efe5f5ee4ad1990c3ee0fd6e4e836 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1565,7 +1565,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1563,7 +1563,7 @@ public abstract class LivingEntity extends Entity implements Attackable { d1 = source.getSourcePosition().z() - this.getZ(); } @@ -50,7 +50,7 @@ index 0a4d2abc5b70c5e4e93dc06fe112e2398d9916e7..c9d7589a18e9cee204f4e52368a60aa4 if (!flag) { this.indicateDamage(d0, d1); } -@@ -1622,7 +1622,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1620,7 +1620,7 @@ public abstract class LivingEntity extends Entity implements Attackable { } protected void blockedByShield(LivingEntity target) { @@ -59,7 +59,7 @@ index 0a4d2abc5b70c5e4e93dc06fe112e2398d9916e7..c9d7589a18e9cee204f4e52368a60aa4 } private boolean checkTotemDeathProtection(DamageSource source) { -@@ -1908,10 +1908,10 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1906,10 +1906,10 @@ public abstract class LivingEntity extends Entity implements Attackable { public void knockback(double strength, double x, double z) { // CraftBukkit start - EntityKnockbackEvent @@ -72,7 +72,7 @@ index 0a4d2abc5b70c5e4e93dc06fe112e2398d9916e7..c9d7589a18e9cee204f4e52368a60aa4 d0 *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); if (true || d0 > 0.0D) { // CraftBukkit - Call event even when force is 0 //this.hasImpulse = true; // CraftBukkit - Move down -@@ -1924,13 +1924,17 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1922,13 +1922,17 @@ public abstract class LivingEntity extends Entity implements Attackable { Vec3 vec3d1 = (new Vec3(d1, 0.0D, d2)).normalize().scale(d0); diff --git a/patches/server/0202-Expand-Explosions-API.patch b/patches/server/0202-Expand-Explosions-API.patch index b9a5452eb8..1952633714 100644 --- a/patches/server/0202-Expand-Explosions-API.patch +++ b/patches/server/0202-Expand-Explosions-API.patch @@ -9,10 +9,10 @@ Co-authored-by: Esoteric Enderman <90862990+EsotericEnderman@users.noreply.githu Co-authored-by: Bjarne Koll diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 17cb827bc90d980d73719776fca967a1d307ce0a..6283f3496f122d4b0c4ac297943baf469e44aee3 100644 +index 0c0d19708832a49734ea08ae05696e0cb20616e4..3324156c004e0506df8be23050f497d462b4b9c1 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1449,6 +1449,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1419,6 +1419,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } public ServerExplosion explode0(@Nullable Entity entity, @Nullable DamageSource damagesource, @Nullable ExplosionDamageCalculator explosiondamagecalculator, double d0, double d1, double d2, float f, boolean flag, Level.ExplosionInteraction world_a, ParticleOptions particleparam, ParticleOptions particleparam1, Holder holder) { @@ -24,7 +24,7 @@ index 17cb827bc90d980d73719776fca967a1d307ce0a..6283f3496f122d4b0c4ac297943baf46 // CraftBukkit end Explosion.BlockInteraction explosion_effect; -@@ -1480,6 +1485,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1450,6 +1455,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe Explosion.BlockInteraction explosion_effect1 = explosion_effect; Vec3 vec3d = new Vec3(d0, d1, d2); ServerExplosion serverexplosion = new ServerExplosion(this, entity, damagesource, explosiondamagecalculator, vec3d, f, flag, explosion_effect1); diff --git a/patches/server/0207-InventoryCloseEvent-Reason-API.patch b/patches/server/0207-InventoryCloseEvent-Reason-API.patch index 968d1a87f8..8e60427648 100644 --- a/patches/server/0207-InventoryCloseEvent-Reason-API.patch +++ b/patches/server/0207-InventoryCloseEvent-Reason-API.patch @@ -7,10 +7,10 @@ Allows you to determine why an inventory was closed, enabling plugin developers to "confirm" things based on if it was player triggered close or not. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 6283f3496f122d4b0c4ac297943baf469e44aee3..425c22fe94e83d880b331cbfb16dc67f22def1c7 100644 +index 3324156c004e0506df8be23050f497d462b4b9c1..75b2caba214c312f9afdd231ee3d75689380a5f3 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1234,7 +1234,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1204,7 +1204,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) { if (tileentity instanceof net.minecraft.world.Container) { for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) { @@ -19,7 +19,7 @@ index 6283f3496f122d4b0c4ac297943baf469e44aee3..425c22fe94e83d880b331cbfb16dc67f } } } -@@ -2279,7 +2279,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2249,7 +2249,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Spigot Start if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) { @@ -75,10 +75,10 @@ index 98aeafcc51e23a7534c8d57e4db0eb58abb3f30b..29b836a75b835f0d5233db419fc5ca8d this.doCloseContainer(); } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 752460c4650bebb2860bea82ca186a0f97b1692b..5f514f87b171c5c845d5d7714d2d2179fbb0c1a1 100644 +index 79d9a58c66382fd94ab5f6020285e341b0114f6a..f36d72153c1ec0426790ed3033500c3cb766af2d 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2641,10 +2641,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2638,10 +2638,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @Override public void handleContainerClose(ServerboundContainerClosePacket packet) { @@ -96,10 +96,10 @@ index 752460c4650bebb2860bea82ca186a0f97b1692b..5f514f87b171c5c845d5d7714d2d2179 this.player.doCloseContainer(); } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 95b9341859ba6da6945faebf8430a044cc1ee828..038c5f16e60f0e182774e6df5b6c5359153a4b07 100644 +index a929c809dc1dcb2bdab4db0d2a8ca794189e93d9..c9c3ebcb7239bf01617a89f03cd0ad12dd0b2c34 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -469,7 +469,7 @@ public abstract class PlayerList { +@@ -468,7 +468,7 @@ public abstract class PlayerList { // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it // See SPIGOT-5799, SPIGOT-6145 if (entityplayer.containerMenu != entityplayer.inventoryMenu) { diff --git a/patches/server/0214-Option-to-prevent-armor-stands-from-doing-entity-loo.patch b/patches/server/0214-Option-to-prevent-armor-stands-from-doing-entity-loo.patch index db5ae6ef64..8f032f18fa 100644 --- a/patches/server/0214-Option-to-prevent-armor-stands-from-doing-entity-loo.patch +++ b/patches/server/0214-Option-to-prevent-armor-stands-from-doing-entity-loo.patch @@ -17,10 +17,10 @@ index aea97a30a9226275f8fbf9cb2c15d5ddf36371ac..e9d6211eb0f955eb95d2f73ad96799ef Iterator iterator = list.iterator(); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index c628524274110bcad175472dbcb82e6c62476a12..3ccd28193bec6363eb87f916589310ee8b45dd3a 100644 +index e0986a141384de0ede38c88c2b116e083c63efe4..fb68aff87670f545ae5ba26db9f074a34375031e 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -766,6 +766,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -759,6 +759,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // Paper end - Prevent block entity and entity crashes } } diff --git a/patches/server/0215-Vanished-players-don-t-have-rights.patch b/patches/server/0215-Vanished-players-don-t-have-rights.patch index 3bdc5087c3..dd1cb5bca9 100644 --- a/patches/server/0215-Vanished-players-don-t-have-rights.patch +++ b/patches/server/0215-Vanished-players-don-t-have-rights.patch @@ -39,10 +39,10 @@ index 752929f3bcd6404b08dad1c67e9a0023b671f10d..407f5db0a4b3884440bc49bf4f00d9c0 BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), defaultReturn); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 3ccd28193bec6363eb87f916589310ee8b45dd3a..cf422de89f0ed81e7c9759328e28ca6b190283ef 100644 +index fb68aff87670f545ae5ba26db9f074a34375031e..924b496aaaa19c7ef69498730725ae9287e46e28 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -265,6 +265,45 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -263,6 +263,45 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); } diff --git a/patches/server/0221-Break-up-and-make-tab-spam-limits-configurable.patch b/patches/server/0221-Break-up-and-make-tab-spam-limits-configurable.patch index ceaa06bf27..92f889e9c0 100644 --- a/patches/server/0221-Break-up-and-make-tab-spam-limits-configurable.patch +++ b/patches/server/0221-Break-up-and-make-tab-spam-limits-configurable.patch @@ -22,7 +22,7 @@ to take the burden of this into their own hand without having to rely on plugins doing unsafe things. diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 5f514f87b171c5c845d5d7714d2d2179fbb0c1a1..4f6985d4458cfba8fd8323d06363763871da2fa0 100644 +index f36d72153c1ec0426790ed3033500c3cb766af2d..af519e9914bae40fa1605b0cd4cf02ca1d44f0e8 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -274,6 +274,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0224-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch b/patches/server/0224-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch index 4338c3faf2..6cd73f5ba7 100644 --- a/patches/server/0224-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch +++ b/patches/server/0224-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add Debug Entities option to debug dupe uuid issues diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 425c22fe94e83d880b331cbfb16dc67f22def1c7..a12d5de8834bbc3176be3d2c8353b2d4372dbc1d 100644 +index 75b2caba214c312f9afdd231ee3d75689380a5f3..0635e7ed67d45abb7c419cf4ebda0e64718b630e 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1196,6 +1196,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1166,6 +1166,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // CraftBukkit start private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot diff --git a/patches/server/0225-Add-Early-Warning-Feature-to-WatchDog.patch b/patches/server/0225-Add-Early-Warning-Feature-to-WatchDog.patch index f6b02a9c46..685cfead73 100644 --- a/patches/server/0225-Add-Early-Warning-Feature-to-WatchDog.patch +++ b/patches/server/0225-Add-Early-Warning-Feature-to-WatchDog.patch @@ -9,10 +9,10 @@ thread dumps at an interval until the point of crash. This will help diagnose what was going on in that time before the crash. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index fe981e45b3b61f24da3e137c68312e98977dad73..87cfbc87198209acfe4354424974afc3cd33f5cd 100644 +index 260d755666efc94e2ea2c8fdb38d7deddda82c08..eb0adba0178a88243946e0c7f39503aa8c7d8feb 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1123,6 +1123,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop collidableExemptions = new HashSet<>(); public boolean bukkitPickUpLoot; public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper @@ -90,7 +90,7 @@ index 35dfaf46429f5478049835e1a5e4b03c362a64e8..a7e950bc5aa827c1b137a12c9eaaf7ea @Override public float getBukkitYaw() { -@@ -1574,11 +1575,12 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1572,11 +1573,12 @@ public abstract class LivingEntity extends Entity implements Attackable { if (this.isDeadOrDying()) { if (!this.checkTotemDeathProtection(source)) { @@ -106,7 +106,7 @@ index 35dfaf46429f5478049835e1a5e4b03c362a64e8..a7e950bc5aa827c1b137a12c9eaaf7ea } } else if (flag1) { this.playHurtSound(source); -@@ -1740,6 +1742,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1738,6 +1740,7 @@ public abstract class LivingEntity extends Entity implements Attackable { Entity entity = damageSource.getEntity(); LivingEntity entityliving = this.getKillCredit(); @@ -114,7 +114,7 @@ index 35dfaf46429f5478049835e1a5e4b03c362a64e8..a7e950bc5aa827c1b137a12c9eaaf7ea if (this.deathScore >= 0 && entityliving != null) { entityliving.awardKillScore(this, this.deathScore, damageSource); } -@@ -1751,24 +1754,59 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1749,24 +1752,59 @@ public abstract class LivingEntity extends Entity implements Attackable { if (!this.level().isClientSide && this.hasCustomName()) { if (org.spigotmc.SpigotConfig.logNamedDeaths) LivingEntity.LOGGER.info("Named entity {} died: {}", this, this.getCombatTracker().getDeathMessage().getString()); // Spigot } @@ -178,7 +178,7 @@ index 35dfaf46429f5478049835e1a5e4b03c362a64e8..a7e950bc5aa827c1b137a12c9eaaf7ea } } -@@ -1778,7 +1816,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1776,7 +1814,7 @@ public abstract class LivingEntity extends Entity implements Attackable { if (world instanceof ServerLevel worldserver) { boolean flag = false; @@ -187,7 +187,7 @@ index 35dfaf46429f5478049835e1a5e4b03c362a64e8..a7e950bc5aa827c1b137a12c9eaaf7ea if (worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { BlockPos blockposition = this.blockPosition(); BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); -@@ -1807,24 +1845,37 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1805,24 +1843,37 @@ public abstract class LivingEntity extends Entity implements Attackable { } } diff --git a/patches/server/0245-Prevent-mob-spawning-from-loading-generating-chunks.patch b/patches/server/0245-Prevent-mob-spawning-from-loading-generating-chunks.patch index 1908c1da0c..e9d396eb02 100644 --- a/patches/server/0245-Prevent-mob-spawning-from-loading-generating-chunks.patch +++ b/patches/server/0245-Prevent-mob-spawning-from-loading-generating-chunks.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Prevent mob spawning from loading/generating chunks also prevents if out of world border bounds diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 0b41149ae134084cef4016241ce923dac0349846..be2412ef8f8c331a881e442577cf05aec43f52bb 100644 +index 5a0ea71dc39c582ef6c843dc0532adb04ba120ce..c826bd20d1ba32ebb9069737ede88e122294ea7a 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -187,9 +187,9 @@ public final class NaturalSpawner { +@@ -185,9 +185,9 @@ public final class NaturalSpawner { StructureManager structuremanager = world.structureManager(); ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator(); int i = pos.getY(); @@ -21,7 +21,7 @@ index 0b41149ae134084cef4016241ce923dac0349846..be2412ef8f8c331a881e442577cf05ae BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); int j = 0; int k = 0; -@@ -218,7 +218,7 @@ public final class NaturalSpawner { +@@ -216,7 +216,7 @@ public final class NaturalSpawner { if (entityhuman != null) { double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); diff --git a/patches/server/0251-Add-LivingEntity-getTargetEntity.patch b/patches/server/0251-Add-LivingEntity-getTargetEntity.patch index 5b17b5d4ff..8f5a3aa5fa 100644 --- a/patches/server/0251-Add-LivingEntity-getTargetEntity.patch +++ b/patches/server/0251-Add-LivingEntity-getTargetEntity.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add LivingEntity#getTargetEntity diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index a7e950bc5aa827c1b137a12c9eaaf7eac867bdc3..b87b59a2ead87b6bda8a8c5bcfd63b128c88f626 100644 +index 7a89c25fcd1c76e4b176c257600db89788aa0f21..3bcf2ba5f065d946ded4020b9882bc4e19af0e08 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4178,6 +4178,38 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -4176,6 +4176,38 @@ public abstract class LivingEntity extends Entity implements Attackable { return this.level().clip(raytrace); } diff --git a/patches/server/0257-Add-option-to-prevent-players-from-moving-into-unloa.patch b/patches/server/0257-Add-option-to-prevent-players-from-moving-into-unloa.patch index 33cebcaddb..a382aa3965 100644 --- a/patches/server/0257-Add-option-to-prevent-players-from-moving-into-unloa.patch +++ b/patches/server/0257-Add-option-to-prevent-players-from-moving-into-unloa.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Add option to prevent players from moving into unloaded diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 4f6985d4458cfba8fd8323d06363763871da2fa0..b15cd1b5b4e4e20a70099acd351e3ac1025a6f31 100644 +index af519e9914bae40fa1605b0cd4cf02ca1d44f0e8..f57c133de5e974d2c86145f697d3636347a29d65 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -498,9 +498,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0260-Improve-Server-Thread-Pool-and-Thread-Priorities.patch b/patches/server/0260-Improve-Server-Thread-Pool-and-Thread-Priorities.patch index 6a48c451fb..71b311db27 100644 --- a/patches/server/0260-Improve-Server-Thread-Pool-and-Thread-Priorities.patch +++ b/patches/server/0260-Improve-Server-Thread-Pool-and-Thread-Priorities.patch @@ -94,10 +94,10 @@ index 8cac2075077b1d9c2b01e09c99780ff9e204abb2..bf2833c92eca6491699b4a89410e4e46 return new TracingExecutor(executorService); } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 87cfbc87198209acfe4354424974afc3cd33f5cd..3c5c3d6d3f95378181a2316337e6f9b910c19003 100644 +index eb0adba0178a88243946e0c7f39503aa8c7d8feb..3669a2943b01e0e9add41df1ff38afd1cd40e96b 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -333,6 +333,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { MinecraftServer.LOGGER.error("Uncaught exception in server thread", throwable); }); diff --git a/patches/server/0261-Optimize-World-Time-Updates.patch b/patches/server/0261-Optimize-World-Time-Updates.patch index 96a00b7577..15bcb78943 100644 --- a/patches/server/0261-Optimize-World-Time-Updates.patch +++ b/patches/server/0261-Optimize-World-Time-Updates.patch @@ -8,12 +8,12 @@ the updates per world, so that we can re-use the same packet object for every player unless they have per-player time enabled. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3c5c3d6d3f95378181a2316337e6f9b910c19003..2011ffeeee5815f667f585d94c5ffdf52ff94884 100644 +index 3669a2943b01e0e9add41df1ff38afd1cd40e96b..a4c897000a5e70e64b5fe4306581b04d8d38bce2 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1639,12 +1639,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements FeatureElement, EntityTypeT +@@ -433,7 +433,7 @@ public class EntityType implements FeatureElement, EntityTypeT @Nullable public T spawn(ServerLevel world, @Nullable ItemStack stack, @Nullable Player player, BlockPos pos, EntitySpawnReason spawnReason, boolean alignPosition, boolean invertY) { // CraftBukkit start diff --git a/patches/server/0280-Add-PlayerPostRespawnEvent.patch b/patches/server/0280-Add-PlayerPostRespawnEvent.patch index 5adb0c50ef..a887fd9918 100644 --- a/patches/server/0280-Add-PlayerPostRespawnEvent.patch +++ b/patches/server/0280-Add-PlayerPostRespawnEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add PlayerPostRespawnEvent diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index dffc7f0c9c730bc629ee169eca3a7a997c2cc7b1..29110c0b950c3073ab699d8ad1523ece2e8d3408 100644 +index fd1fe9a72a1d4e87b97a34fc79ab1429d31207e5..2cfc2213e3036585dc4723eecf747e1c37d53b72 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -705,6 +705,10 @@ public abstract class PlayerList { +@@ -704,6 +704,10 @@ public abstract class PlayerList { entityplayer1.addTag(s); } @@ -19,7 +19,7 @@ index dffc7f0c9c730bc629ee169eca3a7a997c2cc7b1..29110c0b950c3073ab699d8ad1523ece // CraftBukkit start - fire PlayerRespawnEvent TeleportTransition teleporttransition; -@@ -712,11 +716,16 @@ public abstract class PlayerList { +@@ -711,11 +715,16 @@ public abstract class PlayerList { teleporttransition = entityplayer.findRespawnPositionAndUseSpawnBlock(!flag, TeleportTransition.DO_NOTHING, reason); if (!flag) entityplayer.reset(); // SPIGOT-4785 @@ -37,7 +37,7 @@ index dffc7f0c9c730bc629ee169eca3a7a997c2cc7b1..29110c0b950c3073ab699d8ad1523ece return entityplayer; } // Spigot End -@@ -764,6 +773,11 @@ public abstract class PlayerList { +@@ -763,6 +772,11 @@ public abstract class PlayerList { if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) { entityplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 1.0F, 1.0F, worldserver.getRandom().nextLong())); } @@ -49,7 +49,7 @@ index dffc7f0c9c730bc629ee169eca3a7a997c2cc7b1..29110c0b950c3073ab699d8ad1523ece } // Added from changeDimension this.sendAllPlayerInfo(entityplayer); // Update health, etc... -@@ -785,6 +799,13 @@ public abstract class PlayerList { +@@ -784,6 +798,13 @@ public abstract class PlayerList { if (entityplayer.connection.isDisconnected()) { this.save(entityplayer); } diff --git a/patches/server/0281-Server-Tick-Events.patch b/patches/server/0281-Server-Tick-Events.patch index 597da613b9..5e04076791 100644 --- a/patches/server/0281-Server-Tick-Events.patch +++ b/patches/server/0281-Server-Tick-Events.patch @@ -6,21 +6,21 @@ Subject: [PATCH] Server Tick Events Fires event at start and end of a server tick diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7f511a811a73a092ea6a27e4f8afef58dd83b50a..f245b10bc2931ab165057f27a8ff79ea77ea726e 100644 +index 8f427475f7418bbfb8121dbd3e25e7827775ea41..447b8f9ede3f57c6c5f968a0d25153c5c8770c5a 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1504,6 +1504,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop chunkresult = (ChunkResult) completablefuture.join(); + ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error + diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a0a38a78987f05fe47b5a85a49659e7469674210..6e3765b00272548318fca647a80c56ad634b7ecc 100644 +index 800dd7338d77289b7d0e6e126342eaea184d3e43..ecb9f6f0c9b24313b9e55b3a4c4f4bba40bc8fb3 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -412,6 +412,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -410,6 +410,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit } diff --git a/patches/server/0313-Entity-Jump-API.patch b/patches/server/0313-Entity-Jump-API.patch index 290c2cea30..66167bd061 100644 --- a/patches/server/0313-Entity-Jump-API.patch +++ b/patches/server/0313-Entity-Jump-API.patch @@ -7,10 +7,10 @@ Subject: [PATCH] Entity Jump API public net.minecraft.world.entity.LivingEntity jumping diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index f720d4d93ed13b1b9287a1ee7dc8bc4794834e1a..304a401fb1f378ff2cbfd888acf56a8516f79310 100644 +index ebfea3adbedd2695f645421019a276efbc73ee63..724fe482f1711008dc43fef96c4512a18ed54a48 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3539,8 +3539,10 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3537,8 +3537,10 @@ public abstract class LivingEntity extends Entity implements Attackable { } else if (this.isInLava() && (!this.onGround() || d3 > d4)) { this.jumpInLiquid(FluidTags.LAVA); } else if ((this.onGround() || flag && d3 <= d4) && this.noJumpDelay == 0) { diff --git a/patches/server/0320-Optimise-Chunk-getFluid.patch b/patches/server/0320-Optimise-Chunk-getFluid.patch index 1126b881da..b81a71067c 100644 --- a/patches/server/0320-Optimise-Chunk-getFluid.patch +++ b/patches/server/0320-Optimise-Chunk-getFluid.patch @@ -8,7 +8,7 @@ faster on its own, however removing the try catch makes it easier to inline due to code size diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index add5ec0f8e8bd0b89511dcb656e1d4cda702a86b..7181acfafad91aa5f6ab7ce663d9be4a1b65b02a 100644 +index a1b6c13d496519ef6ce240036cec6642626903b9..d4bd4cbc5c4773659662a6d7a09b21a99463c1fb 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -293,18 +293,20 @@ public class LevelChunk extends ChunkAccess { diff --git a/patches/server/0322-Add-tick-times-API-and-mspt-command.patch b/patches/server/0322-Add-tick-times-API-and-mspt-command.patch index 9426f15bec..cbef136961 100644 --- a/patches/server/0322-Add-tick-times-API-and-mspt-command.patch +++ b/patches/server/0322-Add-tick-times-API-and-mspt-command.patch @@ -125,10 +125,10 @@ index 72f2e81b9905a0d57ed8e2a88578f62d5235c456..7b58b2d6297800c2dcdbf7539e5ab8e7 public static void registerCommands(final MinecraftServer server) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index f245b10bc2931ab165057f27a8ff79ea77ea726e..5cc5f4c0a91e7c667e9271de17ffa845f566bd4d 100644 +index 447b8f9ede3f57c6c5f968a0d25153c5c8770c5a..652626c30a5e25ada797ec01273f1e016798aae1 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -264,6 +264,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop entitytypes = entity.getType(); int i = entitytypes.clientTrackingRange() * 16; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 6e3765b00272548318fca647a80c56ad634b7ecc..609c2e1946c86deabb885d7d703cf42273839f1e 100644 +index ecb9f6f0c9b24313b9e55b3a4c4f4bba40bc8fb3..0995a3a274df988a5c63c813de8213019a7c47c4 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2232,7 +2232,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2202,7 +2202,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public void onTrackingStart(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot @@ -37,7 +37,7 @@ index 6e3765b00272548318fca647a80c56ad634b7ecc..609c2e1946c86deabb885d7d703cf422 if (entity instanceof ServerPlayer entityplayer) { ServerLevel.this.players.add(entityplayer); ServerLevel.this.updateSleepingPlayerList(); -@@ -2262,6 +2262,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2232,6 +2232,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe entity.updateDynamicGameEventListener(DynamicGameEventListener::add); entity.inWorld = true; // CraftBukkit - Mark entity as in world entity.valid = true; // CraftBukkit diff --git a/patches/server/0331-Don-t-move-existing-players-to-world-spawn.patch b/patches/server/0331-Don-t-move-existing-players-to-world-spawn.patch index 6750b4fb1a..4c51963248 100644 --- a/patches/server/0331-Don-t-move-existing-players-to-world-spawn.patch +++ b/patches/server/0331-Don-t-move-existing-players-to-world-spawn.patch @@ -35,10 +35,10 @@ index 965ca28a8877f5e541741c45bace7075d15a77d7..adbc8e74f0b454403bc682de11bd0342 this.gameMode.setLevel((ServerLevel) world); } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 29110c0b950c3073ab699d8ad1523ece2e8d3408..074f3518b060c4aa079b1d311b7fcb10d4a95981 100644 +index 2cfc2213e3036585dc4723eecf747e1c37d53b72..ad4f5a4e00b9b517841acd0b4ff5088e45451bf4 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -227,6 +227,7 @@ public abstract class PlayerList { +@@ -226,6 +226,7 @@ public abstract class PlayerList { // Paper start - Entity#getEntitySpawnReason if (optional.isEmpty()) { player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login diff --git a/patches/server/0336-Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/0336-Don-t-run-entity-collision-code-if-not-needed.patch index e0919bb4b1..543230b850 100644 --- a/patches/server/0336-Don-t-run-entity-collision-code-if-not-needed.patch +++ b/patches/server/0336-Don-t-run-entity-collision-code-if-not-needed.patch @@ -12,10 +12,10 @@ The entity's current team collision rule causes them to NEVER collide. Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 304a401fb1f378ff2cbfd888acf56a8516f79310..ecf188d659c8542ca2b52c5e7ec779bfacb5614c 100644 +index 724fe482f1711008dc43fef96c4512a18ed54a48..4fb99e3ee14d2e7fe2720e25af1c890004b0c250 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3683,10 +3683,24 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3681,10 +3681,24 @@ public abstract class LivingEntity extends Entity implements Attackable { if (!(world instanceof ServerLevel worldserver)) { this.level().getEntities(EntityTypeTest.forClass(net.minecraft.world.entity.player.Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush); } else { diff --git a/patches/server/0339-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch b/patches/server/0339-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch index 0863194ba3..d7a416c036 100644 --- a/patches/server/0339-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch +++ b/patches/server/0339-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch @@ -31,10 +31,10 @@ delays anymore. public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 926e1ebfe3a011a28fb82b855511aaabca0c4072..4d8dcc47b39d28ab715110e55110869fe3c9b456 100644 +index 5963f38e050c1ea5c77dde91028d306dfe9b94ba..352675e0b835d5f04576db6599e8840754a40340 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1307,6 +1307,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1305,6 +1305,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return; } // Paper end - ignore and warn about illegal addEntity calls instead of crashing server @@ -55,10 +55,10 @@ index 9911e231ad021286f2da90057b06874f7b4e3b4d..807068fc6065f71961d34cb4f18b6eb3 // CraftBukkit end public boolean isRealPlayer; // Paper diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 074f3518b060c4aa079b1d311b7fcb10d4a95981..ec5673ff22706006a2bcfb5f5a9e8840ee27ac45 100644 +index ad4f5a4e00b9b517841acd0b4ff5088e45451bf4..4ff14dc6996634b0fcd365f76055023601ad2be0 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -300,6 +300,13 @@ public abstract class PlayerList { +@@ -299,6 +299,13 @@ public abstract class PlayerList { this.playersByUUID.put(player.getUUID(), player); // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below @@ -72,7 +72,7 @@ index 074f3518b060c4aa079b1d311b7fcb10d4a95981..ec5673ff22706006a2bcfb5f5a9e8840 // CraftBukkit start CraftPlayer bukkitPlayer = player.getBukkitEntity(); -@@ -338,6 +345,8 @@ public abstract class PlayerList { +@@ -337,6 +344,8 @@ public abstract class PlayerList { player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1))); } player.sentListPacket = true; @@ -81,7 +81,7 @@ index 074f3518b060c4aa079b1d311b7fcb10d4a95981..ec5673ff22706006a2bcfb5f5a9e8840 // CraftBukkit end player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn -@@ -353,8 +362,7 @@ public abstract class PlayerList { +@@ -352,8 +361,7 @@ public abstract class PlayerList { worldserver1 = player.serverLevel(); // CraftBukkit - Update in case join event changed it // CraftBukkit end this.sendActivePlayerEffects(player); diff --git a/patches/server/0340-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/0340-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch index 270260266e..3dae78af46 100644 --- a/patches/server/0340-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch +++ b/patches/server/0340-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch @@ -10,10 +10,10 @@ Co-authored-by: Wyatt Childers Co-authored-by: Jake Potrebic diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index ec5673ff22706006a2bcfb5f5a9e8840ee27ac45..c8c27311ade7d4a70d5398b3a4cb50eedd02a2f9 100644 +index 4ff14dc6996634b0fcd365f76055023601ad2be0..530369764cad77466995f8f65070eec6a5de74f2 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -198,6 +198,7 @@ public abstract class PlayerList { +@@ -197,6 +197,7 @@ public abstract class PlayerList { } Optional optional = this.load(player); // CraftBukkit - decompile error @@ -21,7 +21,7 @@ index ec5673ff22706006a2bcfb5f5a9e8840ee27ac45..c8c27311ade7d4a70d5398b3a4cb50ee // CraftBukkit start - Better rename detection if (optional.isPresent()) { CompoundTag nbttagcompound = optional.get(); -@@ -207,19 +208,47 @@ public abstract class PlayerList { +@@ -206,19 +207,47 @@ public abstract class PlayerList { } } // CraftBukkit end @@ -72,7 +72,7 @@ index ec5673ff22706006a2bcfb5f5a9e8840ee27ac45..c8c27311ade7d4a70d5398b3a4cb50ee } else { worldserver1 = worldserver; } -@@ -227,6 +256,10 @@ public abstract class PlayerList { +@@ -226,6 +255,10 @@ public abstract class PlayerList { // Paper start - Entity#getEntitySpawnReason if (optional.isEmpty()) { player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login diff --git a/patches/server/0341-Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/0341-Add-PlayerAttackEntityCooldownResetEvent.patch index ce70659c90..620e81e210 100644 --- a/patches/server/0341-Add-PlayerAttackEntityCooldownResetEvent.patch +++ b/patches/server/0341-Add-PlayerAttackEntityCooldownResetEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add PlayerAttackEntityCooldownResetEvent diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index ecf188d659c8542ca2b52c5e7ec779bfacb5614c..324d654420c3d11f0695fdf029fde0300a865317 100644 +index 4fb99e3ee14d2e7fe2720e25af1c890004b0c250..25a2085ed68d393afbb658b63a1cd39af98f39fa 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2354,7 +2354,17 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2352,7 +2352,17 @@ public abstract class LivingEntity extends Entity implements Attackable { } if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player) { diff --git a/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch b/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch index 77d7c3a5b2..d818b547f1 100644 --- a/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch +++ b/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch @@ -68,10 +68,10 @@ index 5b8e264098f1b713de15f714bae59d3efda365cf..d5f96ed753e8298085e40c6181285cd6 Iterator iterator = this.getPassengers().iterator(); diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 324d654420c3d11f0695fdf029fde0300a865317..f7323f54b2ac7236d26da8998a88432f9776e1ea 100644 +index 25a2085ed68d393afbb658b63a1cd39af98f39fa..718ccabb46d4520ba363d21a33e06eb2c9ff62ee 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1767,9 +1767,9 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1765,9 +1765,9 @@ public abstract class LivingEntity extends Entity implements Attackable { // Paper start org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(worldserver, damageSource); if (deathEvent == null || !deathEvent.isCancelled()) { @@ -84,7 +84,7 @@ index 324d654420c3d11f0695fdf029fde0300a865317..f7323f54b2ac7236d26da8998a88432f // Paper start - clear equipment if event is not cancelled if (this instanceof Mob) { for (EquipmentSlot slot : this.clearedEquipmentSlots) { -@@ -1863,8 +1863,13 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1861,8 +1861,13 @@ public abstract class LivingEntity extends Entity implements Attackable { this.dropCustomDeathLoot(world, damageSource, flag); this.clearEquipmentSlots = prev; // Paper } diff --git a/patches/server/0346-Validate-PickItem-Packet-and-kick-for-invalid.patch b/patches/server/0346-Validate-PickItem-Packet-and-kick-for-invalid.patch index cc98d91687..6b1b7c3df3 100644 --- a/patches/server/0346-Validate-PickItem-Packet-and-kick-for-invalid.patch +++ b/patches/server/0346-Validate-PickItem-Packet-and-kick-for-invalid.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Validate PickItem Packet and kick for invalid diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index df2718d7e7dd7969f49b3467347fa2adcf60132a..1b82e733c107540618cb1f69511ea9e1a4a13fc8 100644 +index 8a58c1bdda065edd7b8560cd43e805de3fe0b178..59c12f6d5d96835b4b37ed5a761f25f8f147c54a 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -906,7 +906,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0348-misc-debugging-dumps.patch b/patches/server/0348-misc-debugging-dumps.patch index c11d5f369e..64ee1d9744 100644 --- a/patches/server/0348-misc-debugging-dumps.patch +++ b/patches/server/0348-misc-debugging-dumps.patch @@ -49,10 +49,10 @@ index c847fbdb6f52386570eb4c070fcc01d39cc52151..a7eb2a37a81a414dcb19319c075faefe StackTraceElement[] astacktraceelement = exception.getStackTrace(); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 5cc5f4c0a91e7c667e9271de17ffa845f566bd4d..07045495e7d3f7e256bf30a777a5a7536dfe2446 100644 +index 652626c30a5e25ada797ec01273f1e016798aae1..909302aa0afc082a2d0bf55fd31ff9c510e8c3c5 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -931,6 +931,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop task, long delay, long period) throws IllegalArgumentException { diff --git a/patches/server/0364-Prevent-position-desync-causing-tp-exploit.patch b/patches/server/0364-Prevent-position-desync-causing-tp-exploit.patch index ebbd08637a..8b73d196cf 100644 --- a/patches/server/0364-Prevent-position-desync-causing-tp-exploit.patch +++ b/patches/server/0364-Prevent-position-desync-causing-tp-exploit.patch @@ -13,7 +13,7 @@ behaviour, we need to move all of this dangerous logic outside of the move call and into an appropriate place in the tick method. diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 9286012c7a07e1a621035b0563cb06a3421ea945..f4f2b6733780312c289af96ec8ffe1fbf732651e 100644 +index 6c9f7a4d3c7551157d22f17e8a66ada2c50c0550..12827fdd39bb7571739efa482ceb1e32f64ea982 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1359,6 +1359,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0366-Add-PlayerRecipeBookClickEvent.patch b/patches/server/0366-Add-PlayerRecipeBookClickEvent.patch index 504a8bac86..8083914a42 100644 --- a/patches/server/0366-Add-PlayerRecipeBookClickEvent.patch +++ b/patches/server/0366-Add-PlayerRecipeBookClickEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add PlayerRecipeBookClickEvent diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index f4f2b6733780312c289af96ec8ffe1fbf732651e..09b478545ab5eed86dda17c5c74c585c7d3e6df8 100644 +index 12827fdd39bb7571739efa482ceb1e32f64ea982..300f543913979427b28578e5bb3270b20065098c 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -199,6 +199,7 @@ import net.minecraft.world.phys.Vec3; @@ -16,7 +16,7 @@ index f4f2b6733780312c289af96ec8ffe1fbf732651e..09b478545ab5eed86dda17c5c74c585c import org.slf4j.Logger; // CraftBukkit start -@@ -3093,21 +3094,41 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -3090,21 +3091,41 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl ServerGamePacketListenerImpl.LOGGER.debug("Player {} tried to place impossible recipe {}", this.player, recipeholder.id().location()); return; } diff --git a/patches/server/0368-Add-permission-for-command-blocks.patch b/patches/server/0368-Add-permission-for-command-blocks.patch index f971d5b25a..0a7fb386cc 100644 --- a/patches/server/0368-Add-permission-for-command-blocks.patch +++ b/patches/server/0368-Add-permission-for-command-blocks.patch @@ -18,7 +18,7 @@ index 4623c8acd125dff4919c4e2045b848310d785da5..86e4559da2344f228ef4d1c4ac3c115f return false; } else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) { diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 09b478545ab5eed86dda17c5c74c585c7d3e6df8..acf13898f316c0ddf3c31c0ac716322c23234318 100644 +index 300f543913979427b28578e5bb3270b20065098c..0884f71d3264c2a09d2a0958d4751962e4156526 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -818,7 +818,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0370-Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/0370-Fix-Per-World-Difficulty-Remembering-Difficulty.patch index feb2f98133..95cf927bee 100644 --- a/patches/server/0370-Fix-Per-World-Difficulty-Remembering-Difficulty.patch +++ b/patches/server/0370-Fix-Per-World-Difficulty-Remembering-Difficulty.patch @@ -8,10 +8,10 @@ makes it so that the server keeps the last difficulty used instead of restoring the server.properties every single load. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 075928ac5095f95789839c82b528f60b356918b3..1be085de963e1c4e5b5b1902f8dc46b120846226 100644 +index 03d6045fd5721b32852a357f1f2e3d2e16efb85b..fce70aa2b0d92c6291720b75a07a6472eb55855b 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -852,7 +852,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 -@@ -3091,6 +3093,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -3088,6 +3090,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @Override public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { diff --git a/patches/server/0452-Fix-interact-event-not-being-called-sometimes.patch b/patches/server/0452-Fix-interact-event-not-being-called-sometimes.patch index aba682dc6c..72c54e87a3 100644 --- a/patches/server/0452-Fix-interact-event-not-being-called-sometimes.patch +++ b/patches/server/0452-Fix-interact-event-not-being-called-sometimes.patch @@ -11,7 +11,7 @@ Subject: [PATCH] Fix interact event not being called sometimes Co-authored-by: Moulberry diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index bca6e44c6a6584be2537d8be1279497b3394c447..0254ca5ed57de292ecd17900bb4f3d2874e12556 100644 +index f2c1893677004b1699beb16ebfcbe9816aad2a78..03e87e35f4478d948602569c319a7b5a0e938cd5 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1785,7 +1785,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @@ -23,7 +23,7 @@ index bca6e44c6a6584be2537d8be1279497b3394c447..0254ca5ed57de292ecd17900bb4f3d28 this.player.swing(enumhand, true); } } -@@ -2409,13 +2409,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2406,13 +2406,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl double d3 = Math.max(this.player.blockInteractionRange(), this.player.entityInteractionRange()); // 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 // SPIGOT-7429: Make sure to call PlayerInteractEvent for spectators and non-pickable entities diff --git a/patches/server/0457-Add-ServerResourcesReloadedEvent.patch b/patches/server/0457-Add-ServerResourcesReloadedEvent.patch index efe5237d8b..71fc31fbfd 100644 --- a/patches/server/0457-Add-ServerResourcesReloadedEvent.patch +++ b/patches/server/0457-Add-ServerResourcesReloadedEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add ServerResourcesReloadedEvent diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index a26e3620346b80b00e2ca29e7f393bca404d8a50..c4882d30b64c3dd7efe44c38ff130c045d5549d8 100644 +index f6667d9f514a821fd539e193dde1f78e77ca0fbf..264d0f57422b4fc03c5845d7456b22c9a48dd7ae 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2194,7 +2194,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop completablefuture = CompletableFuture.supplyAsync(() -> { Stream stream = dataPacks.stream(); // CraftBukkit - decompile error PackRepository resourcepackrepository = this.packRepository; -@@ -2229,6 +2235,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { this.getServer().execute(() -> { diff --git a/patches/server/0465-Fix-villager-boat-exploit.patch b/patches/server/0465-Fix-villager-boat-exploit.patch index f35fe8a11e..adb461e1ed 100644 --- a/patches/server/0465-Fix-villager-boat-exploit.patch +++ b/patches/server/0465-Fix-villager-boat-exploit.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix villager boat exploit diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 4975b4222d52eddbb42e9c9cd08eef56859080c8..70b7871091ab9b64d2a5503620a71c3d5585c25d 100644 +index 819fb4ef54dce33ec91604491132771f157c8d83..1e5cc810748af34f591d305055fe00a688213617 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -545,6 +545,14 @@ public abstract class PlayerList { +@@ -544,6 +544,14 @@ public abstract class PlayerList { PlayerList.LOGGER.debug("Removing player mount"); entityplayer.stopRiding(); entity.getPassengersAndSelf().forEach((entity1) -> { diff --git a/patches/server/0466-Add-sendOpLevel-API.patch b/patches/server/0466-Add-sendOpLevel-API.patch index fde6ae317a..c938f70a51 100644 --- a/patches/server/0466-Add-sendOpLevel-API.patch +++ b/patches/server/0466-Add-sendOpLevel-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add sendOpLevel API diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 70b7871091ab9b64d2a5503620a71c3d5585c25d..7676dbe55b4bf6e0472dc0190c01e6ecfcbb464e 100644 +index 1e5cc810748af34f591d305055fe00a688213617..240a0e487ede08d1dd5050812ca4f68db4cd2dd1 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1026,6 +1026,11 @@ public abstract class PlayerList { +@@ -1025,6 +1025,11 @@ public abstract class PlayerList { } private void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel) { @@ -20,7 +20,7 @@ index 70b7871091ab9b64d2a5503620a71c3d5585c25d..7676dbe55b4bf6e0472dc0190c01e6ec if (player.connection != null) { byte b0; -@@ -1040,8 +1045,10 @@ public abstract class PlayerList { +@@ -1039,8 +1044,10 @@ public abstract class PlayerList { player.connection.send(new ClientboundEntityEventPacket(player, b0)); } diff --git a/patches/server/0467-Add-RegistryAccess-for-managing-Registries.patch b/patches/server/0467-Add-RegistryAccess-for-managing-Registries.patch index 2f3085960e..ccdf448b22 100644 --- a/patches/server/0467-Add-RegistryAccess-for-managing-Registries.patch +++ b/patches/server/0467-Add-RegistryAccess-for-managing-Registries.patch @@ -861,7 +861,7 @@ index b4ed857f2437759b71b75d7ab36c986a2fd71dbc..09929f580164abcd1c04061d04c6aa99 @Override public B get(NamespacedKey namespacedKey) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index dd3940c2aacfa835b528a882f3ec5dd4d98bd59f..ee231d93d216571a45b11b49663b2ea91c47a1c7 100644 +index 30675a23a25dc065e09d97b9b08386c9f41989d8..a12dc990a9094e964be2af26a5135e3b798f9666 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -284,7 +284,7 @@ public final class CraftServer implements Server { @@ -873,7 +873,7 @@ index dd3940c2aacfa835b528a882f3ec5dd4d98bd59f..ee231d93d216571a45b11b49663b2ea9 private YamlConfiguration configuration; private YamlConfiguration commandsConfiguration; private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); -@@ -432,6 +432,7 @@ public final class CraftServer implements Server { +@@ -431,6 +431,7 @@ public final class CraftServer implements Server { } private void loadCompatibilities() { @@ -881,7 +881,7 @@ index dd3940c2aacfa835b528a882f3ec5dd4d98bd59f..ee231d93d216571a45b11b49663b2ea9 ConfigurationSection compatibilities = this.configuration.getConfigurationSection("settings.compatibility"); if (compatibilities == null) { this.activeCompatibilities = Collections.emptySet(); -@@ -2745,7 +2746,7 @@ public final class CraftServer implements Server { +@@ -2744,7 +2745,7 @@ public final class CraftServer implements Server { @Override public Registry getRegistry(Class aClass) { diff --git a/patches/server/0480-Add-EntityMoveEvent.patch b/patches/server/0480-Add-EntityMoveEvent.patch index 977aa2c046..6dfa7990a6 100644 --- a/patches/server/0480-Add-EntityMoveEvent.patch +++ b/patches/server/0480-Add-EntityMoveEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add EntityMoveEvent diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index c4882d30b64c3dd7efe44c38ff130c045d5549d8..a6435cc675bca502994a31d2f2d91257c8c1fa2f 100644 +index 264d0f57422b4fc03c5845d7456b22c9a48dd7ae..a200aacb1eaa749baa36be8be63b3f1421913b60 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1684,6 +1684,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent @@ -17,10 +17,10 @@ index c4882d30b64c3dd7efe44c38ff130c045d5549d8..a6435cc675bca502994a31d2f2d91257 gameprofilerfiller.push(() -> { String s = String.valueOf(worldserver); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 840651df480dfc6e494240aaa46ea4063171c0de..12f46c94710830f464ff27a3d415140c36065e10 100644 +index 0e984f3521b578779dd9d0142bce7db433b78f07..1c3f41d7ed7320342fe68c5ab6eb57dbdfd4bf69 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -231,6 +231,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -229,6 +229,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public final LevelStorageSource.LevelStorageAccess convertable; public final UUID uuid; public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent @@ -29,10 +29,10 @@ index 840651df480dfc6e494240aaa46ea4063171c0de..12f46c94710830f464ff27a3d415140c public LevelChunk getChunkIfLoaded(int x, int z) { return this.chunkSource.getChunk(x, z, false); diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 5a551e24be8d4d8157adb0f20f8e7bd3c5c61854..8bb10bcc26577ff7b806fbcc48c3d71b241c5963 100644 +index d361e39ba50958e7bdaea0b95c37d13f48a89771..ce9369e730ba8862cd1e6e26f8825c35b16fcfb9 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3628,6 +3628,20 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3626,6 +3626,20 @@ public abstract class LivingEntity extends Entity implements Attackable { this.pushEntities(); gameprofilerfiller.pop(); diff --git a/patches/server/0481-added-option-to-disable-pathfinding-updates-on-block.patch b/patches/server/0481-added-option-to-disable-pathfinding-updates-on-block.patch index c2bfd19f14..d10ca06ced 100644 --- a/patches/server/0481-added-option-to-disable-pathfinding-updates-on-block.patch +++ b/patches/server/0481-added-option-to-disable-pathfinding-updates-on-block.patch @@ -5,10 +5,10 @@ Subject: [PATCH] added option to disable pathfinding updates on block changes diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 12f46c94710830f464ff27a3d415140c36065e10..8352e42a3dceb33477c5885433d24840e1332b87 100644 +index 1c3f41d7ed7320342fe68c5ab6eb57dbdfd4bf69..cefd68cd2f28e5c14dba99b31d9a88125f169337 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1387,6 +1387,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1357,6 +1357,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.getChunkSource().blockChanged(pos); this.pathTypesByPosCache.invalidate(pos); @@ -16,7 +16,7 @@ index 12f46c94710830f464ff27a3d415140c36065e10..8352e42a3dceb33477c5885433d24840 VoxelShape voxelshape = oldState.getCollisionShape(this, pos); VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); -@@ -1428,6 +1429,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1398,6 +1399,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } diff --git a/patches/server/0484-Add-getMainThreadExecutor-to-BukkitScheduler.patch b/patches/server/0484-Add-getMainThreadExecutor-to-BukkitScheduler.patch index e2b8629ca8..ead28f59cb 100644 --- a/patches/server/0484-Add-getMainThreadExecutor-to-BukkitScheduler.patch +++ b/patches/server/0484-Add-getMainThreadExecutor-to-BukkitScheduler.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add getMainThreadExecutor to BukkitScheduler diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index fdfdcac6644e5343fb1f1cbe5d9aa76a79627046..5fc88196b2c873427c817e9802ad3b12009f265f 100644 +index a700dac93499650fdaa0af06ff77607ffa4dbbb2..6fef86e47e37eab6721cfd67d494afb25a2ded68 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -642,4 +642,15 @@ public class CraftScheduler implements BukkitScheduler { +@@ -637,4 +637,15 @@ public class CraftScheduler implements BukkitScheduler { public BukkitTask runTaskTimerAsynchronously(Plugin plugin, BukkitRunnable task, long delay, long period) throws IllegalArgumentException { throw new UnsupportedOperationException("Use BukkitRunnable#runTaskTimerAsynchronously(Plugin, long, long)"); } diff --git a/patches/server/0490-fix-converting-txt-to-json-file.patch b/patches/server/0490-fix-converting-txt-to-json-file.patch index 19ad568347..130584b001 100644 --- a/patches/server/0490-fix-converting-txt-to-json-file.patch +++ b/patches/server/0490-fix-converting-txt-to-json-file.patch @@ -21,10 +21,10 @@ index 929f59bce01c8e6ed4b0b551744d42e131b8fc80..22c4f8dea99f92a1eb3da2baf0a15bf9 this.saveUserBanList(); this.loadIpBanList(); diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 20a3138c6c2a6c8ada8b6008913abae0eea76f2d..e95d592b6001dd4320c58133d841359f99c2d9c4 100644 +index 9a3e73a5c206b78dfcf6f41a47b614342e52acc8..9d05e998d6df1069c2de69478a1f9688ac435e67 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -215,6 +215,12 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -213,6 +213,12 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess()); this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); // Paper end - initialize global and world-defaults configuration @@ -37,7 +37,7 @@ index 20a3138c6c2a6c8ada8b6008913abae0eea76f2d..e95d592b6001dd4320c58133d841359f org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics -@@ -269,9 +275,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -267,9 +273,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface DedicatedServer.LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file."); } @@ -48,10 +48,10 @@ index 20a3138c6c2a6c8ada8b6008913abae0eea76f2d..e95d592b6001dd4320c58133d841359f if (!OldUsersConverter.serverReadyAfterUserconversion(this)) { return false; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 7676dbe55b4bf6e0472dc0190c01e6ecfcbb464e..26e0414645f7ab11ca3e77c7c5e458612625aee9 100644 +index 240a0e487ede08d1dd5050812ca4f68db4cd2dd1..82f5451add3652d9f1afba4f809f30ceaa1b2951 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -180,6 +180,7 @@ public abstract class PlayerList { +@@ -179,6 +179,7 @@ public abstract class PlayerList { this.maxPlayers = maxPlayers; this.playerIo = saveHandler; } diff --git a/patches/server/0495-Allow-using-signs-inside-spawn-protection.patch b/patches/server/0495-Allow-using-signs-inside-spawn-protection.patch index 09955d8b69..cbb5462bf6 100644 --- a/patches/server/0495-Allow-using-signs-inside-spawn-protection.patch +++ b/patches/server/0495-Allow-using-signs-inside-spawn-protection.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Allow using signs inside spawn protection diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0254ca5ed57de292ecd17900bb4f3d2874e12556..d93dfaf50c48b1975d59f9aa24b895f151d2e1b1 100644 +index 03e87e35f4478d948602569c319a7b5a0e938cd5..03ab4e27e141716e1c9ae92d41f42cfb7a48db66 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1770,7 +1770,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0496-Expand-world-key-API.patch b/patches/server/0496-Expand-world-key-API.patch index da317765ce..80f4011a34 100644 --- a/patches/server/0496-Expand-world-key-API.patch +++ b/patches/server/0496-Expand-world-key-API.patch @@ -20,10 +20,10 @@ index 15da29058f80a2d7cf2be26c48421c1746815a10..a070b2a83edaa702b13bc6d302691412 // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index ee231d93d216571a45b11b49663b2ea91c47a1c7..dc20a383950a72aba5d056912d257912d3c0e808 100644 +index a12dc990a9094e964be2af26a5135e3b798f9666..85b2298efface87ee97e0f996d939cc135ca981d 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1186,9 +1186,15 @@ public final class CraftServer implements Server { +@@ -1185,9 +1185,15 @@ public final class CraftServer implements Server { File folder = new File(this.getWorldContainer(), name); World world = this.getWorld(name); @@ -41,7 +41,7 @@ index ee231d93d216571a45b11b49663b2ea91c47a1c7..dc20a383950a72aba5d056912d257912 if (folder.exists()) { Preconditions.checkArgument(folder.isDirectory(), "File (%s) exists and isn't a folder", name); -@@ -1314,7 +1320,7 @@ public final class CraftServer implements Server { +@@ -1313,7 +1319,7 @@ public final class CraftServer implements Server { } else if (name.equals(levelName + "_the_end")) { worldKey = net.minecraft.world.level.Level.END; } else { @@ -50,7 +50,7 @@ index ee231d93d216571a45b11b49663b2ea91c47a1c7..dc20a383950a72aba5d056912d257912 } // If set to not keep spawn in memory (changed from default) then adjust rule accordingly -@@ -1410,6 +1416,15 @@ public final class CraftServer implements Server { +@@ -1409,6 +1415,15 @@ public final class CraftServer implements Server { return null; } @@ -67,10 +67,10 @@ index ee231d93d216571a45b11b49663b2ea91c47a1c7..dc20a383950a72aba5d056912d257912 // Check if a World already exists with the UID. if (this.getWorld(world.getUID()) != null) { diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 6e8351363af9aea752286311074d53f245196e8d..e53610ac0ef0c80932e6e50f0c3971938b4bcf9b 100644 +index af8fde74b3162d2de740ecae1122b4f2115baeb6..77f0d6c44c3773968b1e858d02cfc4ffb25fe99b 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -522,6 +522,11 @@ public final class CraftMagicNumbers implements UnsafeValues { +@@ -527,6 +527,11 @@ public final class CraftMagicNumbers implements UnsafeValues { public int nextEntityId() { return net.minecraft.world.entity.Entity.nextEntityId(); } @@ -81,4 +81,4 @@ index 6e8351363af9aea752286311074d53f245196e8d..e53610ac0ef0c80932e6e50f0c397193 + } // Paper end - @Override + /** diff --git a/patches/server/0498-Drop-carried-item-when-player-has-disconnected.patch b/patches/server/0498-Drop-carried-item-when-player-has-disconnected.patch index a13f458eea..bebcb8d121 100644 --- a/patches/server/0498-Drop-carried-item-when-player-has-disconnected.patch +++ b/patches/server/0498-Drop-carried-item-when-player-has-disconnected.patch @@ -7,10 +7,10 @@ Fixes disappearance of held items, when a player gets disconnected and PlayerDro Closes #5036 diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 26e0414645f7ab11ca3e77c7c5e458612625aee9..6f7807cc0da427485037b3a72a9c60c81a858294 100644 +index 82f5451add3652d9f1afba4f809f30ceaa1b2951..7a18061834096a73b140bee37b55b3c1724b51ef 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -538,6 +538,14 @@ public abstract class PlayerList { +@@ -537,6 +537,14 @@ public abstract class PlayerList { } // Paper end - Configurable player collision diff --git a/patches/server/0499-forced-whitelist-use-configurable-kick-message.patch b/patches/server/0499-forced-whitelist-use-configurable-kick-message.patch index 6dcbff2ff8..e3d3ef89a7 100644 --- a/patches/server/0499-forced-whitelist-use-configurable-kick-message.patch +++ b/patches/server/0499-forced-whitelist-use-configurable-kick-message.patch @@ -5,10 +5,10 @@ Subject: [PATCH] forced whitelist: use configurable kick message diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index a6435cc675bca502994a31d2f2d91257c8c1fa2f..1cf78a61a5737aafd4e9384dc76af1a9fbc98621 100644 +index a200aacb1eaa749baa36be8be63b3f1421913b60..67a9bc450f545dd7b05398968a278a14f1e518fe 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2369,7 +2369,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop getDefaultAttributeModifiers(Material material, EquipmentSlot slot) { diff --git a/patches/server/0536-Add-cause-to-Weather-ThunderChangeEvents.patch b/patches/server/0536-Add-cause-to-Weather-ThunderChangeEvents.patch index 9e50f7f9b7..ef0b70b8d8 100644 --- a/patches/server/0536-Add-cause-to-Weather-ThunderChangeEvents.patch +++ b/patches/server/0536-Add-cause-to-Weather-ThunderChangeEvents.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add cause to Weather/ThunderChangeEvents diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 8352e42a3dceb33477c5885433d24840e1332b87..1be314ed35d07e6db9a3f6a4f493b0f4bb59a45f 100644 +index cefd68cd2f28e5c14dba99b31d9a88125f169337..f58069f0c9d836cb33f3ea09c562708951a91797 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -431,8 +431,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -429,8 +429,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.serverLevelData.setClearWeatherTime(clearDuration); this.serverLevelData.setRainTime(rainDuration); this.serverLevelData.setThunderTime(rainDuration); @@ -19,7 +19,7 @@ index 8352e42a3dceb33477c5885433d24840e1332b87..1be314ed35d07e6db9a3f6a4f493b0f4 } @Override -@@ -862,8 +862,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -846,8 +846,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.serverLevelData.setThunderTime(j); this.serverLevelData.setRainTime(k); this.serverLevelData.setClearWeatherTime(i); @@ -30,7 +30,7 @@ index 8352e42a3dceb33477c5885433d24840e1332b87..1be314ed35d07e6db9a3f6a4f493b0f4 } this.oThunderLevel = this.thunderLevel; -@@ -930,14 +930,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -914,14 +914,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @VisibleForTesting public void resetWeatherCycle() { // CraftBukkit start diff --git a/patches/server/0539-Add-PlayerKickEvent-causes.patch b/patches/server/0539-Add-PlayerKickEvent-causes.patch index 1ba9b46938..7c4ea36fb3 100644 --- a/patches/server/0539-Add-PlayerKickEvent-causes.patch +++ b/patches/server/0539-Add-PlayerKickEvent-causes.patch @@ -43,10 +43,10 @@ index dbcf183483766f39334d7f7e8336033906625f3f..300929a406905f5ff1ede664d5b99fb0 } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 1cf78a61a5737aafd4e9384dc76af1a9fbc98621..f191209b9a1d581235a638bd89ee2eb4050d5cb0 100644 +index 67a9bc450f545dd7b05398968a278a14f1e518fe..7ab9a9c04f94a68dccb5ec9bfc8171bfc02927a2 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2369,7 +2369,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 4096) { @@ -384,7 +384,7 @@ index 674149f3a392a600a506e55f20db044619328cd2..0fb16f3193c88c5f58d16aaf85129bbf } } -@@ -2599,7 +2599,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2596,7 +2596,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // Spigot Start if ( entity == this.player && !this.player.isSpectator() ) { @@ -393,7 +393,7 @@ index 674149f3a392a600a506e55f20db044619328cd2..0fb16f3193c88c5f58d16aaf85129bbf return; } // Spigot End -@@ -2715,7 +2715,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2712,7 +2712,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } } @@ -402,7 +402,7 @@ index 674149f3a392a600a506e55f20db044619328cd2..0fb16f3193c88c5f58d16aaf85129bbf ServerGamePacketListenerImpl.LOGGER.warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getName().getString()); } }); -@@ -3114,7 +3114,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -3111,7 +3111,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // Paper start - auto recipe limit if (!org.bukkit.Bukkit.isPrimaryThread()) { if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) { @@ -411,7 +411,7 @@ index 674149f3a392a600a506e55f20db044619328cd2..0fb16f3193c88c5f58d16aaf85129bbf return; } } -@@ -3385,7 +3385,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -3382,7 +3382,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl if (!Objects.equals(profilepublickey_a, profilepublickey_a1)) { if (profilepublickey_a != null && profilepublickey_a1.expiresAt().isBefore(profilepublickey_a.expiresAt())) { @@ -420,7 +420,7 @@ index 674149f3a392a600a506e55f20db044619328cd2..0fb16f3193c88c5f58d16aaf85129bbf } else { try { SignatureValidator signaturevalidator = this.server.getProfileKeySignatureValidator(); -@@ -3398,7 +3398,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -3395,7 +3395,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.resetPlayerChatState(remotechatsession_a.validate(this.player.getGameProfile(), signaturevalidator)); } catch (ProfilePublicKey.ValidationException profilepublickey_b) { ServerGamePacketListenerImpl.LOGGER.error("Failed to validate profile key: {}", profilepublickey_b.getMessage()); @@ -443,10 +443,10 @@ index 9d5723cdfdbf6257a71e57842aea9ba317fc049a..1e4b288f20153ce0c91fabf164c5c832 } // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 6f7807cc0da427485037b3a72a9c60c81a858294..3ec8d38ca514048d94d24424d2132a90c10f529f 100644 +index 7a18061834096a73b140bee37b55b3c1724b51ef..e6b92f085291aaf4fa78d96f8379aeef2200592b 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -633,7 +633,7 @@ public abstract class PlayerList { +@@ -632,7 +632,7 @@ public abstract class PlayerList { while (iterator.hasNext()) { entityplayer = (ServerPlayer) iterator.next(); this.save(entityplayer); // CraftBukkit - Force the player's inventory to be saved @@ -455,7 +455,7 @@ index 6f7807cc0da427485037b3a72a9c60c81a858294..3ec8d38ca514048d94d24424d2132a90 } // Instead of kicking then returning, we need to store the kick reason -@@ -1238,7 +1238,7 @@ public abstract class PlayerList { +@@ -1236,7 +1236,7 @@ public abstract class PlayerList { // Paper end // CraftBukkit start - disconnect safely for (ServerPlayer player : this.players) { diff --git a/patches/server/0548-Line-Of-Sight-Changes.patch b/patches/server/0548-Line-Of-Sight-Changes.patch index d8a956a309..0b72d78709 100644 --- a/patches/server/0548-Line-Of-Sight-Changes.patch +++ b/patches/server/0548-Line-Of-Sight-Changes.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Line Of Sight Changes diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 9829419d3531ed6af55e37ac253903975c648a3e..1cb118c12e1b09cb6ae8d3b6949212b46c91b85b 100644 +index 9d56e7d4185401767359907337d5891ff0058abb..8939ce9fed5d935cec31c9a27833d1cec4de7b01 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3907,7 +3907,8 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3905,7 +3905,8 @@ public abstract class LivingEntity extends Entity implements Attackable { Vec3 vec3d = new Vec3(this.getX(), this.getEyeY(), this.getZ()); Vec3 vec3d1 = new Vec3(entity.getX(), entityY.getAsDouble(), entity.getZ()); diff --git a/patches/server/0555-Use-getChunkIfLoadedImmediately-in-places.patch b/patches/server/0555-Use-getChunkIfLoadedImmediately-in-places.patch index a5b4d06295..99a97d953d 100644 --- a/patches/server/0555-Use-getChunkIfLoadedImmediately-in-places.patch +++ b/patches/server/0555-Use-getChunkIfLoadedImmediately-in-places.patch @@ -8,10 +8,10 @@ ticket level 33 (yes getChunkIfLoaded will actually perform a chunk load in that case). diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 1be314ed35d07e6db9a3f6a4f493b0f4bb59a45f..d8f7d7512db9432f67b07e7d64a6a9349dfab245 100644 +index f58069f0c9d836cb33f3ea09c562708951a91797..91fb83761885752743adb53cc9ed30ddc879263d 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -234,7 +234,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -232,7 +232,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent public LevelChunk getChunkIfLoaded(int x, int z) { @@ -21,10 +21,10 @@ index 1be314ed35d07e6db9a3f6a4f493b0f4bb59a45f..d8f7d7512db9432f67b07e7d64a6a934 @Override diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index aff89d2e3274b91238989fc1e7d8c119c2a3c097..560777a99b58c4f82cc0e8fb087de04a564163b5 100644 +index 71e9c1504d4b85ffb695401974748d56fefb66e6..9536e127ff4d45ca59b74fe0f3dbde9a18c04f42 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -180,6 +180,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -179,6 +179,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public CraftServer getCraftServer() { return (CraftServer) Bukkit.getServer(); } diff --git a/patches/server/0557-Add-PlayerArmSwingEvent.patch b/patches/server/0557-Add-PlayerArmSwingEvent.patch index c334885378..5b14fa047d 100644 --- a/patches/server/0557-Add-PlayerArmSwingEvent.patch +++ b/patches/server/0557-Add-PlayerArmSwingEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add PlayerArmSwingEvent diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0fb16f3193c88c5f58d16aaf85129bbfd01fdfcd..7e11789a8d64b112c5eb354a30ae9618722526b1 100644 +index 36127f7c9ae50a628e88e7b456889a8f259b06da..e48c6f37ba0ebe698e28042e9331ab2ec0c39e7c 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2431,7 +2431,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2428,7 +2428,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } // Paper end - Call interact event // Arm swing animation diff --git a/patches/server/0558-Fix-kick-event-leave-message-not-being-sent.patch b/patches/server/0558-Fix-kick-event-leave-message-not-being-sent.patch index 0068fffc6e..170b51853d 100644 --- a/patches/server/0558-Fix-kick-event-leave-message-not-being-sent.patch +++ b/patches/server/0558-Fix-kick-event-leave-message-not-being-sent.patch @@ -55,7 +55,7 @@ index 59d20fd62e850a38380d877cef95ed69cb46ecbd..fc242acade3ff06c9213428cde103cf0 MinecraftServer minecraftserver = this.server; Connection networkmanager = this.connection; diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 7e11789a8d64b112c5eb354a30ae9618722526b1..a550f23227770001862e5e837ab2f09e746d76f1 100644 +index e48c6f37ba0ebe698e28042e9331ab2ec0c39e7c..0229b3e6c27b142ff726de8e2e15104a6acbc1f0 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1915,6 +1915,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @@ -101,10 +101,10 @@ index 7e11789a8d64b112c5eb354a30ae9618722526b1..a550f23227770001862e5e837ab2f09e this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(quitMessage), false); // Paper end diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 3ec8d38ca514048d94d24424d2132a90c10f529f..55e1e8ab83e8ca44735a0b1a7365526d0a3b24e7 100644 +index e6b92f085291aaf4fa78d96f8379aeef2200592b..adba2f7632df2e876c22ebe3a5232d93f6581282 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -511,6 +511,11 @@ public abstract class PlayerList { +@@ -510,6 +510,11 @@ public abstract class PlayerList { } public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // CraftBukkit - return string // Paper - return Component diff --git a/patches/server/0560-Rate-options-and-timings-for-sensors-and-behaviors.patch b/patches/server/0560-Rate-options-and-timings-for-sensors-and-behaviors.patch index 3f0d6720ed..3473ea4ceb 100644 --- a/patches/server/0560-Rate-options-and-timings-for-sensors-and-behaviors.patch +++ b/patches/server/0560-Rate-options-and-timings-for-sensors-and-behaviors.patch @@ -8,41 +8,21 @@ This adds config options to specify the tick rate for sensors for those in order to be able to have some metrics as to which ones might need tweaking. -diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java -index 4bd813161a5d76a83cdbd0a9209b9ea9e60ffe1b..e2764186bd6b838ed5cd86c15597a08d079ef984 100644 ---- a/src/main/java/co/aikar/timings/MinecraftTimings.java -+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java -@@ -115,6 +115,14 @@ public final class MinecraftTimings { - return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType + " - " + type, tickEntityTimer); - } - -+ public static Timing getBehaviorTimings(String type) { -+ return Timings.ofSafe("## Behavior - " + type); -+ } -+ -+ public static Timing getSensorTimings(String type, int rate) { -+ return Timings.ofSafe("## Sensor - " + type + " (Default rate: " + rate + ")"); -+ } -+ - /** - * Get a named timer for the specified tile entity type to track type specific timings. - * @param entity diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java -index f639cafa64d98a001e622882c647701547f5c3ac..9379dd4056018b52c93ed4888dcdc94579bd9691 100644 +index f639cafa64d98a001e622882c647701547f5c3ac..ba951cc1aaa94b58ee7985f197d41cc8be747fc8 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java -@@ -14,6 +14,10 @@ public abstract class Behavior implements BehaviorContro +@@ -14,6 +14,9 @@ public abstract class Behavior implements BehaviorContro private long endTimestamp; private final int minDuration; private final int maxDuration; + // Paper start - configurable behavior tick rate and timings + private final String configKey; -+ private final co.aikar.timings.Timing timing; + // Paper end - configurable behavior tick rate and timings public Behavior(Map, MemoryStatus> requiredMemoryState) { this(requiredMemoryState, 60); -@@ -27,6 +31,15 @@ public abstract class Behavior implements BehaviorContro +@@ -27,6 +30,14 @@ public abstract class Behavior implements BehaviorContro this.minDuration = minRunTime; this.maxDuration = maxRunTime; this.entryCondition = requiredMemoryState; @@ -53,12 +33,11 @@ index f639cafa64d98a001e622882c647701547f5c3ac..9379dd4056018b52c93ed4888dcdc945 + key = key.substring(lastSeparator + 1); + } + this.configKey = key.toLowerCase(java.util.Locale.ROOT); -+ this.timing = co.aikar.timings.MinecraftTimings.getBehaviorTimings(configKey); + // Paper end - configurable behavior tick rate and timings } @Override -@@ -36,11 +49,19 @@ public abstract class Behavior implements BehaviorContro +@@ -36,6 +47,12 @@ public abstract class Behavior implements BehaviorContro @Override public final boolean tryStart(ServerLevel world, E entity, long time) { @@ -71,38 +50,16 @@ index f639cafa64d98a001e622882c647701547f5c3ac..9379dd4056018b52c93ed4888dcdc945 if (this.hasRequiredMemories(entity) && this.checkExtraStartConditions(world, entity)) { this.status = Behavior.Status.RUNNING; int i = this.minDuration + world.getRandom().nextInt(this.maxDuration + 1 - this.minDuration); - this.endTimestamp = time + (long)i; -+ this.timing.startTiming(); // Paper - behavior timings - this.start(world, entity, time); -+ this.timing.stopTiming(); // Paper - behavior timings - return true; - } else { - return false; -@@ -52,11 +73,13 @@ public abstract class Behavior implements BehaviorContro - - @Override - public final void tickOrStop(ServerLevel world, E entity, long time) { -+ this.timing.startTiming(); // Paper - behavior timings - if (!this.timedOut(time) && this.canStillUse(world, entity, time)) { - this.tick(world, entity, time); - } else { - this.doStop(world, entity, time); - } -+ this.timing.stopTiming(); // Paper - behavior timings - } - - protected void tick(ServerLevel world, E entity, long time) { diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java -index 4d451f6cb5862411848bb9b6b5692ab512dcaa25..8bc7979fb9c2a796921a2a279b78294809f2ed03 100644 +index 4d451f6cb5862411848bb9b6b5692ab512dcaa25..fb1f5375eafb030ae08c735a80e9c8149726cda4 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java -@@ -29,8 +29,21 @@ public abstract class Sensor { +@@ -29,8 +29,19 @@ public abstract class Sensor { .ignoreInvisibilityTesting(); private final int scanRate; private long timeToTick; + // Paper start - configurable sensor tick rate and timings + private final String configKey; -+ private final co.aikar.timings.Timing timing; + // Paper end public Sensor(int senseInterval) { @@ -113,23 +70,19 @@ index 4d451f6cb5862411848bb9b6b5692ab512dcaa25..8bc7979fb9c2a796921a2a279b782948 + key = key.substring(lastSeparator + 1); + } + this.configKey = key.toLowerCase(java.util.Locale.ROOT); -+ this.timing = co.aikar.timings.MinecraftTimings.getSensorTimings(configKey, senseInterval); + // Paper end this.scanRate = senseInterval; this.timeToTick = (long)RANDOM.nextInt(senseInterval); } -@@ -41,9 +54,13 @@ public abstract class Sensor { +@@ -41,8 +52,10 @@ public abstract class Sensor { public final void tick(ServerLevel world, E entity) { if (--this.timeToTick <= 0L) { - this.timeToTick = (long)this.scanRate; + // Paper start - configurable sensor tick rate and timings + this.timeToTick = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.sensor.get(entity.getType(), this.configKey), this.scanRate); -+ this.timing.startTiming(); this.updateTargetingConditionRanges(entity); + // Paper end this.doTick(world, entity); -+ this.timing.stopTiming(); // Paper - sensor timings } } - diff --git a/patches/server/0563-Add-System.out-err-catcher.patch b/patches/server/0563-Add-System.out-err-catcher.patch index c975b94d8f..1904f817de 100644 --- a/patches/server/0563-Add-System.out-err-catcher.patch +++ b/patches/server/0563-Add-System.out-err-catcher.patch @@ -105,7 +105,7 @@ index 0000000000000000000000000000000000000000..a8e813ca89b033f061e695288b3383bd + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index d921b15100b83cb7073d79f2a1b2bfbdc7b745ca..35e5a3dc58f93b85f93ec5301cc9b5c7505503bc 100644 +index a17b26dadbbbf6e6c84f80f6fe8293d87ca19d0a..ecf7ee1ca39d58f1780580bd24366fc8037df34a 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -310,6 +310,7 @@ public final class CraftServer implements Server { diff --git a/patches/server/0564-Prevent-AFK-kick-while-watching-end-credits.patch b/patches/server/0564-Prevent-AFK-kick-while-watching-end-credits.patch index 3413c09bda..dc3eed68eb 100644 --- a/patches/server/0564-Prevent-AFK-kick-while-watching-end-credits.patch +++ b/patches/server/0564-Prevent-AFK-kick-while-watching-end-credits.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Prevent AFK kick while watching end credits diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index a550f23227770001862e5e837ab2f09e746d76f1..ea793f9ccf3082a7abcb003b9df03901f9b4c0f0 100644 +index 0229b3e6c27b142ff726de8e2e15104a6acbc1f0..70b891bd018029eda8cda4fb9f919e77524dbc5e 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -396,7 +396,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl diff --git a/patches/server/0566-Add-PlayerSetSpawnEvent.patch b/patches/server/0566-Add-PlayerSetSpawnEvent.patch index 6c4f8f48bc..d290efd766 100644 --- a/patches/server/0566-Add-PlayerSetSpawnEvent.patch +++ b/patches/server/0566-Add-PlayerSetSpawnEvent.patch @@ -154,10 +154,10 @@ index 94cc69ed1ccbcfcc8f431762fef641c313b2f634..c680b311760601bb539d685bceddba67 public SectionPos getLastSectionPos() { diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 55e1e8ab83e8ca44735a0b1a7365526d0a3b24e7..1b6540ae28d73501c59581b1864f0e01ab53e365 100644 +index adba2f7632df2e876c22ebe3a5232d93f6581282..dd7b19a7762b91a8b27717098cebd2c48cb96f68 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -803,7 +803,7 @@ public abstract class PlayerList { +@@ -802,7 +802,7 @@ public abstract class PlayerList { // CraftBukkit end if (teleporttransition.missingRespawnBlock()) { entityplayer1.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F)); diff --git a/patches/server/0574-Add-BlockBreakBlockEvent.patch b/patches/server/0574-Add-BlockBreakBlockEvent.patch index 4a3af0251e..fbd3627b5c 100644 --- a/patches/server/0574-Add-BlockBreakBlockEvent.patch +++ b/patches/server/0574-Add-BlockBreakBlockEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add BlockBreakBlockEvent diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 43c2b411115d3a8a0e47d3e2277789b2667897af..4d140bd83ca0e1554afad80ec4fc6186188a79d8 100644 +index f1711f774f844024ca7b678385daaace6cda9f46..9d8c4ecd89b05a0e5d4ebb5e686eba5d899765f2 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -304,6 +304,24 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -295,6 +295,24 @@ public class Block extends BlockBehaviour implements ItemLike { } diff --git a/patches/server/0579-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/server/0579-Add-methods-to-find-targets-for-lightning-strikes.patch index 6727d31ea6..0a2ba7ccde 100644 --- a/patches/server/0579-Add-methods-to-find-targets-for-lightning-strikes.patch +++ b/patches/server/0579-Add-methods-to-find-targets-for-lightning-strikes.patch @@ -7,10 +7,10 @@ Subject: [PATCH] Add methods to find targets for lightning strikes public net.minecraft.server.level.ServerLevel findLightningRod(Lnet/minecraft/core/BlockPos;)Ljava/util/Optional; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index d8f7d7512db9432f67b07e7d64a6a9349dfab245..3137738307bb7b43190fa65da26e0b038012a9f4 100644 +index 91fb83761885752743adb53cc9ed30ddc879263d..3c281cdd24acbc9484c968c07f737d50be2deced 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -751,6 +751,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -735,6 +735,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } protected BlockPos findLightningTargetAround(BlockPos pos) { @@ -22,7 +22,7 @@ index d8f7d7512db9432f67b07e7d64a6a9349dfab245..3137738307bb7b43190fa65da26e0b03 BlockPos blockposition1 = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); Optional optional = this.findLightningRod(blockposition1); -@@ -765,6 +770,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -749,6 +754,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (!list.isEmpty()) { return ((LivingEntity) list.get(this.random.nextInt(list.size()))).blockPosition(); } else { diff --git a/patches/server/0580-Get-entity-default-attributes.patch b/patches/server/0580-Get-entity-default-attributes.patch index ef862f64a6..6d512ca637 100644 --- a/patches/server/0580-Get-entity-default-attributes.patch +++ b/patches/server/0580-Get-entity-default-attributes.patch @@ -81,10 +81,10 @@ index 0000000000000000000000000000000000000000..ec9ebd2d539333293c51b7edfa18f18b + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 7e33f55e4a269fd8e96080776c97f49d65e895c4..c9e0a2a4c7c8ab50f6dbb6079f2cba06652a92a3 100644 +index ffc98d8ed238cc653a7a6518a46c4e45a1b3682c..31b625779dfe27602ac198259258e64195c1796d 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -544,6 +544,18 @@ public final class CraftMagicNumbers implements UnsafeValues { +@@ -549,6 +549,18 @@ public final class CraftMagicNumbers implements UnsafeValues { } return CraftItemStack.unwrap(itemToBeRepaired).isValidRepairItem(CraftItemStack.unwrap(repairMaterial)); } @@ -102,7 +102,7 @@ index 7e33f55e4a269fd8e96080776c97f49d65e895c4..c9e0a2a4c7c8ab50f6dbb6079f2cba06 + } // Paper end - @Override + /** diff --git a/src/test/java/io/papermc/paper/attribute/EntityTypeAttributesTest.java b/src/test/java/io/papermc/paper/attribute/EntityTypeAttributesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f512d416df883036965ff6c802fd242a4c9c8079 diff --git a/patches/server/0589-Add-Raw-Byte-Entity-Serialization.patch b/patches/server/0589-Add-Raw-Byte-Entity-Serialization.patch index 5a6f0f6000..0b866c52fb 100644 --- a/patches/server/0589-Add-Raw-Byte-Entity-Serialization.patch +++ b/patches/server/0589-Add-Raw-Byte-Entity-Serialization.patch @@ -50,10 +50,10 @@ index 0c1c9033646dedcf1d11dee74d6965683adadf0a..1ed01978611cddb2558e441863dadc46 @Override public boolean isInvisible() { // Paper - moved up from LivingEntity diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index c9e0a2a4c7c8ab50f6dbb6079f2cba06652a92a3..8d51786837448db1a96d0071293025d07e14c225 100644 +index 31b625779dfe27602ac198259258e64195c1796d..1ab160c3d042be43df3bd19d095534b91c4c2f71 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -494,7 +494,33 @@ public final class CraftMagicNumbers implements UnsafeValues { +@@ -499,7 +499,33 @@ public final class CraftMagicNumbers implements UnsafeValues { return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow()); } diff --git a/patches/server/0591-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch b/patches/server/0591-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch index 8404f01faa..27c3f61502 100644 --- a/patches/server/0591-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch +++ b/patches/server/0591-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch @@ -9,10 +9,10 @@ chunk through it. This should also be OK from a leak prevention/ state desync POV because the TE is getting unloaded anyways. diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 3137738307bb7b43190fa65da26e0b038012a9f4..0485312d40dca972d2477b8d4a4725ff25deacbc 100644 +index 3c281cdd24acbc9484c968c07f737d50be2deced..ecb4dc0642685d67621c82bb24fb0e939c805ce4 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1269,9 +1269,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1239,9 +1239,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Spigot Start for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) { if (tileentity instanceof net.minecraft.world.Container) { diff --git a/patches/server/0593-Improve-and-expand-AsyncCatcher.patch b/patches/server/0593-Improve-and-expand-AsyncCatcher.patch index 921cb5a829..0e27a17c00 100644 --- a/patches/server/0593-Improve-and-expand-AsyncCatcher.patch +++ b/patches/server/0593-Improve-and-expand-AsyncCatcher.patch @@ -17,7 +17,7 @@ Async catch modifications to critical entity state Co-authored-by: Jake Potrebic diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index ea793f9ccf3082a7abcb003b9df03901f9b4c0f0..8084bf547a52f3e5c890d2be3757acb364370d34 100644 +index 70b891bd018029eda8cda4fb9f919e77524dbc5e..a4abcbc69ccd023a936d02d359ba4c08198ed31e 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1597,6 +1597,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @@ -29,10 +29,10 @@ index ea793f9ccf3082a7abcb003b9df03901f9b4c0f0..8084bf547a52f3e5c890d2be3757acb3 if (player.isRemoved()) { LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 1cb118c12e1b09cb6ae8d3b6949212b46c91b85b..21f9fc5c3111dc126d0197a02bb61541fc422933 100644 +index 8939ce9fed5d935cec31c9a27833d1cec4de7b01..564024738cc346abc024967c2d55f2553af3e660 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1145,7 +1145,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1143,7 +1143,7 @@ public abstract class LivingEntity extends Entity implements Attackable { } public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { diff --git a/patches/server/0594-Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/0594-Add-paper-mobcaps-and-paper-playermobcaps.patch index b998ef75b4..2eb0c23389 100644 --- a/patches/server/0594-Add-paper-mobcaps-and-paper-playermobcaps.patch +++ b/patches/server/0594-Add-paper-mobcaps-and-paper-playermobcaps.patch @@ -257,10 +257,10 @@ index 0000000000000000000000000000000000000000..d3b39d88a72ca25057fd8574d32f28db + } +} diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 485c6044d603f15878f9413a644a538dab68db3e..6eb69ebe688c1c52d5a5986dfc63cdd42e66687e 100644 +index 606a60fe273974b71ed2bd40be819d848627e777..bf943feca387b77a3154773a59da7190d38d8621 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -174,6 +174,16 @@ public final class NaturalSpawner { +@@ -172,6 +172,16 @@ public final class NaturalSpawner { gameprofilerfiller.pop(); } @@ -278,10 +278,10 @@ index 485c6044d603f15878f9413a644a538dab68db3e..6eb69ebe688c1c52d5a5986dfc63cdd4 BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 35e5a3dc58f93b85f93ec5301cc9b5c7505503bc..f69504676d2f48f3778f489ec1e08e2b3dec85cc 100644 +index ecf7ee1ca39d58f1780580bd24366fc8037df34a..1c72862b3167acc05f06b44cd9a0929ad8d2b9c8 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2335,6 +2335,11 @@ public final class CraftServer implements Server { +@@ -2334,6 +2334,11 @@ public final class CraftServer implements Server { @Override public int getSpawnLimit(SpawnCategory spawnCategory) { diff --git a/patches/server/0598-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch b/patches/server/0598-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch index e87128411d..9efbcafadb 100644 --- a/patches/server/0598-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch +++ b/patches/server/0598-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch @@ -10,10 +10,10 @@ chunks did get inlined, but the standard CPS.getChunkAt method was not inlined. diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 560777a99b58c4f82cc0e8fb087de04a564163b5..8269bf24f5e17f9e3936659aa0cbc9d4f95fb665 100644 +index 9536e127ff4d45ca59b74fe0f3dbde9a18c04f42..9afc0eaaca5ab7b6445d90ce53e31a6ae76f8848 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -352,7 +352,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -350,7 +350,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline diff --git a/patches/server/0601-Oprimise-map-impl-for-tracked-players.patch b/patches/server/0601-Oprimise-map-impl-for-tracked-players.patch new file mode 100644 index 0000000000..026136cdd5 --- /dev/null +++ b/patches/server/0601-Oprimise-map-impl-for-tracked-players.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 19 Feb 2021 22:51:52 -0800 +Subject: [PATCH] Oprimise map impl for tracked players + +Reference2BooleanOpenHashMap is going to have +better lookups than HashMap. + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 352675e0b835d5f04576db6599e8840754a40340..b92a889d0b0c46c1fa247d770f303d7d37dfc36c 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1514,7 +1514,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + final Entity entity; + private final int range; + SectionPos lastSectionPos; +- public final Set seenBy = Sets.newIdentityHashSet(); ++ public final Set seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl + + public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) { + this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit diff --git a/patches/server/0601-Time-scoreboard-search.patch b/patches/server/0601-Time-scoreboard-search.patch deleted file mode 100644 index 8d15084758..0000000000 --- a/patches/server/0601-Time-scoreboard-search.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 21 Apr 2020 01:53:22 -0700 -Subject: [PATCH] Time scoreboard search - -Plugins leaking scoreboards will make this very expensive, -let server owners debug it easily - -diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java -index e2764186bd6b838ed5cd86c15597a08d079ef984..6b3cde6d4d1e63bec01f502f2027ee9fddac08aa 100644 ---- a/src/main/java/co/aikar/timings/MinecraftTimings.java -+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java -@@ -46,6 +46,7 @@ public final class MinecraftTimings { - - public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update"); - public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate"); -+ public static final Timing scoreboardScoreSearch = Timings.ofSafe("Scoreboard score search"); // Paper - add timings for scoreboard search - - private static final Map, String> taskNameCache = new MapMaker().weakKeys().makeMap(); - -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -index c7ca6210d6ae37fe95068c9baa5fb654f95307e0..cad42a0f3c016bf65181e50d139ae4e2fb9158a5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -@@ -113,9 +113,18 @@ public final class CraftScoreboardManager implements ScoreboardManager { - - // CraftBukkit method - public void forAllObjectives(ObjectiveCriteria criteria, ScoreHolder holder, Consumer consumer) { -+ // Paper start - add timings for scoreboard search -+ // plugins leaking scoreboards will make this very expensive, let server owners debug it easily -+ co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.startTimingIfSync(); -+ try { -+ // Paper end - add timings for scoreboard search - for (CraftScoreboard scoreboard : this.scoreboards) { - Scoreboard board = scoreboard.board; - board.forAllObjectives(criteria, holder, (score) -> consumer.accept(score)); - } -+ } finally { // Paper start - add timings for scoreboard search -+ co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.stopTimingIfSync(); -+ } -+ // Paper end - add timings for scoreboard search - } - } diff --git a/patches/server/0602-Add-missing-InventoryType.patch b/patches/server/0602-Add-missing-InventoryType.patch new file mode 100644 index 0000000000..a49bdf073d --- /dev/null +++ b/patches/server/0602-Add-missing-InventoryType.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 27 Dec 2023 16:46:07 -0800 +Subject: [PATCH] Add missing InventoryType + +Upstream did not add a DECORATED_POT inventory type + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +index 3b0d3e9a067fccb10122c273aaf658ba240aa716..af1ae3dacb628da23f7d2988c6e76d3fb2d64103 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +@@ -541,6 +541,10 @@ public class CraftInventory implements Inventory { + return InventoryType.COMPOSTER; + } else if (this.inventory instanceof JukeboxBlockEntity) { + return InventoryType.JUKEBOX; ++ // Paper start ++ } else if (this.inventory instanceof net.minecraft.world.level.block.entity.DecoratedPotBlockEntity) { ++ return org.bukkit.event.inventory.InventoryType.DECORATED_POT; ++ // Paper end + } else { + return InventoryType.CHEST; + } diff --git a/patches/server/0602-Oprimise-map-impl-for-tracked-players.patch b/patches/server/0602-Oprimise-map-impl-for-tracked-players.patch deleted file mode 100644 index c0bbabf27c..0000000000 --- a/patches/server/0602-Oprimise-map-impl-for-tracked-players.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 19 Feb 2021 22:51:52 -0800 -Subject: [PATCH] Oprimise map impl for tracked players - -Reference2BooleanOpenHashMap is going to have -better lookups than HashMap. - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 4d8dcc47b39d28ab715110e55110869fe3c9b456..75854574aa8d4aef35d84ba4c0fc7df9a67ae48c 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1520,7 +1520,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - final Entity entity; - private final int range; - SectionPos lastSectionPos; -- public final Set seenBy = Sets.newIdentityHashSet(); -+ public final Set seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl - - public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) { - this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit diff --git a/patches/server/0603-Add-missing-InventoryType.patch b/patches/server/0603-Add-missing-InventoryType.patch deleted file mode 100644 index a49bdf073d..0000000000 --- a/patches/server/0603-Add-missing-InventoryType.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 27 Dec 2023 16:46:07 -0800 -Subject: [PATCH] Add missing InventoryType - -Upstream did not add a DECORATED_POT inventory type - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -index 3b0d3e9a067fccb10122c273aaf658ba240aa716..af1ae3dacb628da23f7d2988c6e76d3fb2d64103 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -@@ -541,6 +541,10 @@ public class CraftInventory implements Inventory { - return InventoryType.COMPOSTER; - } else if (this.inventory instanceof JukeboxBlockEntity) { - return InventoryType.JUKEBOX; -+ // Paper start -+ } else if (this.inventory instanceof net.minecraft.world.level.block.entity.DecoratedPotBlockEntity) { -+ return org.bukkit.event.inventory.InventoryType.DECORATED_POT; -+ // Paper end - } else { - return InventoryType.CHEST; - } diff --git a/patches/server/0603-Optimise-BlockSoil-nearby-water-lookup.patch b/patches/server/0603-Optimise-BlockSoil-nearby-water-lookup.patch new file mode 100644 index 0000000000..4a5d6c5b9d --- /dev/null +++ b/patches/server/0603-Optimise-BlockSoil-nearby-water-lookup.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Thu, 10 Jun 2021 14:36:00 -0700 +Subject: [PATCH] Optimise BlockSoil nearby water lookup + +Apparently the abstract block iteration was taking about +75% of the method call. + +diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java +index a87f8345aa5520a867a8dd769b43526b20b8c16a..c3dba0c2c94f3804338f86621dc42405e380a6b3 100644 +--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java +@@ -154,19 +154,28 @@ public class FarmBlock extends Block { + } + + private static boolean isNearWater(LevelReader world, BlockPos pos) { +- Iterator iterator = BlockPos.betweenClosed(pos.offset(-4, 0, -4), pos.offset(4, 1, 4)).iterator(); +- +- BlockPos blockposition1; +- +- do { +- if (!iterator.hasNext()) { +- return false; ++ // Paper start - Perf: remove abstract block iteration ++ int xOff = pos.getX(); ++ int yOff = pos.getY(); ++ int zOff = pos.getZ(); ++ ++ for (int dz = -4; dz <= 4; ++dz) { ++ int z = dz + zOff; ++ for (int dx = -4; dx <= 4; ++dx) { ++ int x = xOff + dx; ++ for (int dy = 0; dy <= 1; ++dy) { ++ int y = dy + yOff; ++ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)world.getChunk(x >> 4, z >> 4); ++ net.minecraft.world.level.material.FluidState fluid = chunk.getBlockStateFinal(x, y, z).getFluidState(); ++ if (fluid.is(FluidTags.WATER)) { ++ return true; ++ } ++ } + } ++ } + +- blockposition1 = (BlockPos) iterator.next(); +- } while (!world.getFluidState(blockposition1).is(FluidTags.WATER)); +- +- return true; ++ return false; ++ // Paper end - Perf: remove abstract block iteration + } + + @Override diff --git a/patches/server/0604-Fix-merchant-inventory-not-closing-on-entity-removal.patch b/patches/server/0604-Fix-merchant-inventory-not-closing-on-entity-removal.patch new file mode 100644 index 0000000000..87e006c31f --- /dev/null +++ b/patches/server/0604-Fix-merchant-inventory-not-closing-on-entity-removal.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 2 Sep 2021 00:24:06 -0700 +Subject: [PATCH] Fix merchant inventory not closing on entity removal + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index ecb4dc0642685d67621c82bb24fb0e939c805ce4..3b3024fcf39266cc6ae61fb77dbffb391dc96c92 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2298,6 +2298,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // Spigot end + // Spigot Start + if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message ++ // Paper start - Fix merchant inventory not closing on entity removal ++ if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { ++ merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); ++ } ++ // Paper end - Fix merchant inventory not closing on entity removal + for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) { + h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason + } diff --git a/patches/server/0604-Optimise-BlockSoil-nearby-water-lookup.patch b/patches/server/0604-Optimise-BlockSoil-nearby-water-lookup.patch deleted file mode 100644 index 4a5d6c5b9d..0000000000 --- a/patches/server/0604-Optimise-BlockSoil-nearby-water-lookup.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 10 Jun 2021 14:36:00 -0700 -Subject: [PATCH] Optimise BlockSoil nearby water lookup - -Apparently the abstract block iteration was taking about -75% of the method call. - -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index a87f8345aa5520a867a8dd769b43526b20b8c16a..c3dba0c2c94f3804338f86621dc42405e380a6b3 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -154,19 +154,28 @@ public class FarmBlock extends Block { - } - - private static boolean isNearWater(LevelReader world, BlockPos pos) { -- Iterator iterator = BlockPos.betweenClosed(pos.offset(-4, 0, -4), pos.offset(4, 1, 4)).iterator(); -- -- BlockPos blockposition1; -- -- do { -- if (!iterator.hasNext()) { -- return false; -+ // Paper start - Perf: remove abstract block iteration -+ int xOff = pos.getX(); -+ int yOff = pos.getY(); -+ int zOff = pos.getZ(); -+ -+ for (int dz = -4; dz <= 4; ++dz) { -+ int z = dz + zOff; -+ for (int dx = -4; dx <= 4; ++dx) { -+ int x = xOff + dx; -+ for (int dy = 0; dy <= 1; ++dy) { -+ int y = dy + yOff; -+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)world.getChunk(x >> 4, z >> 4); -+ net.minecraft.world.level.material.FluidState fluid = chunk.getBlockStateFinal(x, y, z).getFluidState(); -+ if (fluid.is(FluidTags.WATER)) { -+ return true; -+ } -+ } - } -+ } - -- blockposition1 = (BlockPos) iterator.next(); -- } while (!world.getFluidState(blockposition1).is(FluidTags.WATER)); -- -- return true; -+ return false; -+ // Paper end - Perf: remove abstract block iteration - } - - @Override diff --git a/patches/server/0605-Check-requirement-before-suggesting-root-nodes.patch b/patches/server/0605-Check-requirement-before-suggesting-root-nodes.patch new file mode 100644 index 0000000000..fce5e326f9 --- /dev/null +++ b/patches/server/0605-Check-requirement-before-suggesting-root-nodes.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: stonar96 +Date: Sun, 12 Sep 2021 00:14:21 +0200 +Subject: [PATCH] Check requirement before suggesting root nodes + +Child nodes are handled by CommandDispatcher#parse checking +requirements. + +Vanilla clients only send ServerboundCommandSuggestionPacket when +encountering a command node with ASK_SERVER suggestions, however a +modified client can send this packet whenever it wants. + +diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +index 858e41fba7dc285dd21a93f3918cc5de3887df5f..92848b64a78fce7a92e1657c2da6fc5ee53eea44 100644 +--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java ++++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +@@ -538,10 +538,14 @@ public class CommandDispatcher { + int i = 0; + for (final CommandNode node : parent.getChildren()) { + CompletableFuture future = Suggestions.empty(); ++ // Paper start - Don't suggest if the requirement isn't met ++ if (parent != this.root || node.canUse(context.getSource())) { + try { +- if (node.canUse(parse.getContext().getSource())) future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit ++ future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit + } catch (final CommandSyntaxException ignored) { + } ++ } ++ // Paper end - Don't suggest if the requirement isn't met + futures[i++] = future; + } + diff --git a/patches/server/0605-Fix-merchant-inventory-not-closing-on-entity-removal.patch b/patches/server/0605-Fix-merchant-inventory-not-closing-on-entity-removal.patch deleted file mode 100644 index 4b017db5b6..0000000000 --- a/patches/server/0605-Fix-merchant-inventory-not-closing-on-entity-removal.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 2 Sep 2021 00:24:06 -0700 -Subject: [PATCH] Fix merchant inventory not closing on entity removal - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0485312d40dca972d2477b8d4a4725ff25deacbc..3ca2c0d937dc840ac64fb1efd73dbc5b045bc77d 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2328,6 +2328,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Spigot end - // Spigot Start - if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message -+ // Paper start - Fix merchant inventory not closing on entity removal -+ if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { -+ merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); -+ } -+ // Paper end - Fix merchant inventory not closing on entity removal - for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) { - h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason - } diff --git a/patches/server/0606-Check-requirement-before-suggesting-root-nodes.patch b/patches/server/0606-Check-requirement-before-suggesting-root-nodes.patch deleted file mode 100644 index fce5e326f9..0000000000 --- a/patches/server/0606-Check-requirement-before-suggesting-root-nodes.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: stonar96 -Date: Sun, 12 Sep 2021 00:14:21 +0200 -Subject: [PATCH] Check requirement before suggesting root nodes - -Child nodes are handled by CommandDispatcher#parse checking -requirements. - -Vanilla clients only send ServerboundCommandSuggestionPacket when -encountering a command node with ASK_SERVER suggestions, however a -modified client can send this packet whenever it wants. - -diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java -index 858e41fba7dc285dd21a93f3918cc5de3887df5f..92848b64a78fce7a92e1657c2da6fc5ee53eea44 100644 ---- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java -+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java -@@ -538,10 +538,14 @@ public class CommandDispatcher { - int i = 0; - for (final CommandNode node : parent.getChildren()) { - CompletableFuture future = Suggestions.empty(); -+ // Paper start - Don't suggest if the requirement isn't met -+ if (parent != this.root || node.canUse(context.getSource())) { - try { -- if (node.canUse(parse.getContext().getSource())) future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit -+ future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit - } catch (final CommandSyntaxException ignored) { - } -+ } -+ // Paper end - Don't suggest if the requirement isn't met - futures[i++] = future; - } - diff --git a/patches/server/0606-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch b/patches/server/0606-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch new file mode 100644 index 0000000000..db870d4240 --- /dev/null +++ b/patches/server/0606-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: stonar96 +Date: Sun, 12 Sep 2021 00:14:21 +0200 +Subject: [PATCH] Don't respond to ServerboundCommandSuggestionPacket when + tab-complete is disabled + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index a4abcbc69ccd023a936d02d359ba4c08198ed31e..7f1e0c6801a1d8b0857fba9826fc56e30bd41497 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -760,6 +760,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + return; + } + // CraftBukkit end ++ // Paper start - Don't suggest if tab-complete is disabled ++ if (org.spigotmc.SpigotConfig.tabComplete < 0) { ++ return; ++ } ++ // Paper end - Don't suggest if tab-complete is disabled + // Paper start - AsyncTabCompleteEvent + TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet)); + } diff --git a/patches/server/0607-Add-packet-limiter-config.patch b/patches/server/0607-Add-packet-limiter-config.patch new file mode 100644 index 0000000000..a6bd6521f4 --- /dev/null +++ b/patches/server/0607-Add-packet-limiter-config.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 30 Oct 2020 22:37:16 -0700 +Subject: [PATCH] Add packet limiter config + +Example config: +packet-limiter: + kick-message: '&cSent too many packets' + limits: + all: + interval: 7.0 + max-packet-rate: 500.0 + ServerboundPlaceRecipePacket: + interval: 4.0 + max-packet-rate: 5.0 + action: DROP + +all section refers to all incoming packets, the action for all is +hard coded to KICK. + +For specific limits, the section name is the class's name, +and an action can be defined: DROP or KICK + +If interval or rate are less-than 0, the limit is ignored + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index 2b86415e4ea197c5c44c23072c9a1cda595544a8..4d9f1fc884050993287adfa4578a87da710623fb 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -137,6 +137,22 @@ public class Connection extends SimpleChannelInboundHandler> { + return null; + } + // Paper end - add utility methods ++ // Paper start - packet limiter ++ protected final Object PACKET_LIMIT_LOCK = new Object(); ++ protected final @Nullable io.papermc.paper.util.IntervalledCounter allPacketCounts = io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.isEnabled() ? new io.papermc.paper.util.IntervalledCounter( ++ (long)(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.interval() * 1.0e9) ++ ) : null; ++ protected final java.util.Map>, io.papermc.paper.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>(); ++ ++ private boolean stopReadingPackets; ++ private void killForPacketSpam() { ++ this.sendPacket(new ClientboundDisconnectPacket(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)), PacketSendListener.thenRun(() -> { ++ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)); ++ }), true); ++ this.setReadOnly(); ++ this.stopReadingPackets = true; ++ } ++ // Paper end - packet limiter + + public Connection(PacketFlow side) { + this.receiving = side; +@@ -215,6 +231,55 @@ public class Connection extends SimpleChannelInboundHandler> { + if (packetlistener == null) { + throw new IllegalStateException("Received a packet before the packet listener was initialized"); + } else { ++ // Paper start - packet limiter ++ if (this.stopReadingPackets) { ++ return; ++ } ++ if (this.allPacketCounts != null || ++ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) { ++ long time = System.nanoTime(); ++ synchronized (PACKET_LIMIT_LOCK) { ++ if (this.allPacketCounts != null) { ++ this.allPacketCounts.updateAndAdd(1, time); ++ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) { ++ this.killForPacketSpam(); ++ return; ++ } ++ } ++ ++ for (Class check = packet.getClass(); check != Object.class; check = check.getSuperclass()) { ++ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit = ++ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check); ++ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) { ++ continue; ++ } ++ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> { ++ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9)); ++ }); ++ counter.updateAndAdd(1, time); ++ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) { ++ switch (packetSpecificLimit.action()) { ++ case DROP: ++ return; ++ case KICK: ++ String deobfedPacketName = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(check.getName()); ++ ++ String playerName; ++ if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) { ++ playerName = impl.getOwner().getName(); ++ } else { ++ playerName = this.getLoggableAddress(net.minecraft.server.MinecraftServer.getServer().logIPs()); ++ } ++ ++ Connection.LOGGER.warn("{} kicked for packet spamming: {}", playerName, deobfedPacketName.substring(deobfedPacketName.lastIndexOf(".") + 1)); ++ this.killForPacketSpam(); ++ return; ++ } ++ } ++ } ++ } ++ } ++ // Paper end - packet limiter + if (packetlistener.shouldHandleMessage(packet)) { + try { + Connection.genericsFtw(packet, packetlistener); diff --git a/patches/server/0607-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch b/patches/server/0607-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch deleted file mode 100644 index 60d634041c..0000000000 --- a/patches/server/0607-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: stonar96 -Date: Sun, 12 Sep 2021 00:14:21 +0200 -Subject: [PATCH] Don't respond to ServerboundCommandSuggestionPacket when - tab-complete is disabled - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 8084bf547a52f3e5c890d2be3757acb364370d34..0790d904a408652c593dc8d87b1b2087169e7490 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -760,6 +760,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - return; - } - // CraftBukkit end -+ // Paper start - Don't suggest if tab-complete is disabled -+ if (org.spigotmc.SpigotConfig.tabComplete < 0) { -+ return; -+ } -+ // Paper end - Don't suggest if tab-complete is disabled - // Paper start - AsyncTabCompleteEvent - TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet)); - } diff --git a/patches/server/0608-Add-packet-limiter-config.patch b/patches/server/0608-Add-packet-limiter-config.patch deleted file mode 100644 index a6bd6521f4..0000000000 --- a/patches/server/0608-Add-packet-limiter-config.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 30 Oct 2020 22:37:16 -0700 -Subject: [PATCH] Add packet limiter config - -Example config: -packet-limiter: - kick-message: '&cSent too many packets' - limits: - all: - interval: 7.0 - max-packet-rate: 500.0 - ServerboundPlaceRecipePacket: - interval: 4.0 - max-packet-rate: 5.0 - action: DROP - -all section refers to all incoming packets, the action for all is -hard coded to KICK. - -For specific limits, the section name is the class's name, -and an action can be defined: DROP or KICK - -If interval or rate are less-than 0, the limit is ignored - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 2b86415e4ea197c5c44c23072c9a1cda595544a8..4d9f1fc884050993287adfa4578a87da710623fb 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -137,6 +137,22 @@ public class Connection extends SimpleChannelInboundHandler> { - return null; - } - // Paper end - add utility methods -+ // Paper start - packet limiter -+ protected final Object PACKET_LIMIT_LOCK = new Object(); -+ protected final @Nullable io.papermc.paper.util.IntervalledCounter allPacketCounts = io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.isEnabled() ? new io.papermc.paper.util.IntervalledCounter( -+ (long)(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.interval() * 1.0e9) -+ ) : null; -+ protected final java.util.Map>, io.papermc.paper.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>(); -+ -+ private boolean stopReadingPackets; -+ private void killForPacketSpam() { -+ this.sendPacket(new ClientboundDisconnectPacket(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)), PacketSendListener.thenRun(() -> { -+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)); -+ }), true); -+ this.setReadOnly(); -+ this.stopReadingPackets = true; -+ } -+ // Paper end - packet limiter - - public Connection(PacketFlow side) { - this.receiving = side; -@@ -215,6 +231,55 @@ public class Connection extends SimpleChannelInboundHandler> { - if (packetlistener == null) { - throw new IllegalStateException("Received a packet before the packet listener was initialized"); - } else { -+ // Paper start - packet limiter -+ if (this.stopReadingPackets) { -+ return; -+ } -+ if (this.allPacketCounts != null || -+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) { -+ long time = System.nanoTime(); -+ synchronized (PACKET_LIMIT_LOCK) { -+ if (this.allPacketCounts != null) { -+ this.allPacketCounts.updateAndAdd(1, time); -+ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) { -+ this.killForPacketSpam(); -+ return; -+ } -+ } -+ -+ for (Class check = packet.getClass(); check != Object.class; check = check.getSuperclass()) { -+ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit = -+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check); -+ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) { -+ continue; -+ } -+ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> { -+ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9)); -+ }); -+ counter.updateAndAdd(1, time); -+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) { -+ switch (packetSpecificLimit.action()) { -+ case DROP: -+ return; -+ case KICK: -+ String deobfedPacketName = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(check.getName()); -+ -+ String playerName; -+ if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) { -+ playerName = impl.getOwner().getName(); -+ } else { -+ playerName = this.getLoggableAddress(net.minecraft.server.MinecraftServer.getServer().logIPs()); -+ } -+ -+ Connection.LOGGER.warn("{} kicked for packet spamming: {}", playerName, deobfedPacketName.substring(deobfedPacketName.lastIndexOf(".") + 1)); -+ this.killForPacketSpam(); -+ return; -+ } -+ } -+ } -+ } -+ } -+ // Paper end - packet limiter - if (packetlistener.shouldHandleMessage(packet)) { - try { - Connection.genericsFtw(packet, packetlistener); diff --git a/patches/server/0608-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch b/patches/server/0608-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch new file mode 100644 index 0000000000..c313451894 --- /dev/null +++ b/patches/server/0608-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bjarne Koll +Date: Sat, 6 Nov 2021 23:15:20 +0100 +Subject: [PATCH] Fix setPatternColor on tropical fish bucket meta + +Prior to this commit, the tropical fish bucket meta would set the body +color to the previous metas pattern colour when updating the pattern +colour. + +This commit hence simply fixes this by using the proper body colour +value when updating the pattern color. + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +index 8169d08c1bccf7c9896bb083eba388f918fac6c9..a514fe98d3d2b65d2cfd029079c69189bcb99c01 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +@@ -128,7 +128,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB + if (this.variant == null) { + this.variant = 0; + } +- this.variant = CraftTropicalFish.getData(color, this.getPatternColor(), this.getPattern()); ++ this.variant = CraftTropicalFish.getData(color, this.getBodyColor(), this.getPattern()); // Paper - properly set tropical fish pattern color without mutating body color + } + + @Override +diff --git a/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..68a557cedbffb41f27ba21096e2ae5eebbf13f5c +--- /dev/null ++++ b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.inventory; ++ ++import org.bukkit.DyeColor; ++import org.bukkit.Material; ++import org.bukkit.entity.TropicalFish; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.inventory.meta.TropicalFishBucketMeta; ++import org.bukkit.support.environment.AllFeatures; ++import org.junit.jupiter.api.Assertions; ++import org.junit.jupiter.api.Test; ++ ++@AllFeatures ++public class CraftMetaTropicalFishBucketTest { ++ ++ @Test ++ public void testAllCombinations() { ++ final var rawMeta = new ItemStack(Material.TROPICAL_FISH_BUCKET).getItemMeta(); ++ Assertions.assertTrue(rawMeta instanceof TropicalFishBucketMeta, "Meta was not a tropical fish bucket"); ++ ++ final var meta = (TropicalFishBucketMeta) rawMeta; ++ ++ for (final var bodyColor : DyeColor.values()) { ++ for (final var pattern : TropicalFish.Pattern.values()) { ++ for (final var patternColor : DyeColor.values()) { ++ meta.setBodyColor(bodyColor); ++ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post body color!"); ++ ++ meta.setPattern(pattern); ++ Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern!"); ++ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern!"); ++ ++ meta.setPatternColor(patternColor); ++ Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern color!"); ++ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern color!"); ++ Assertions.assertEquals(patternColor, meta.getPatternColor(), "Pattern color did not match post pattern color!"); ++ } ++ } ++ } ++ } ++ ++} diff --git a/patches/server/0609-Ensure-valid-vehicle-status.patch b/patches/server/0609-Ensure-valid-vehicle-status.patch new file mode 100644 index 0000000000..c4359b2054 --- /dev/null +++ b/patches/server/0609-Ensure-valid-vehicle-status.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Tue, 28 Sep 2021 09:47:47 +0200 +Subject: [PATCH] Ensure valid vehicle status + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index d2fbbdbb451d6c54d847b4ba125397ad41c4f7b4..f72ab5e4e743cb0758ebca28e81f97c143c91b42 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -698,7 +698,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } + } + +- if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger()) { ++ if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger() && !entity.isRemoved()) { // Paper - Ensure valid vehicle status + // CraftBukkit end + CompoundTag nbttagcompound1 = new CompoundTag(); + CompoundTag nbttagcompound2 = new CompoundTag(); diff --git a/patches/server/0609-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch b/patches/server/0609-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch deleted file mode 100644 index c313451894..0000000000 --- a/patches/server/0609-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bjarne Koll -Date: Sat, 6 Nov 2021 23:15:20 +0100 -Subject: [PATCH] Fix setPatternColor on tropical fish bucket meta - -Prior to this commit, the tropical fish bucket meta would set the body -color to the previous metas pattern colour when updating the pattern -colour. - -This commit hence simply fixes this by using the proper body colour -value when updating the pattern color. - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -index 8169d08c1bccf7c9896bb083eba388f918fac6c9..a514fe98d3d2b65d2cfd029079c69189bcb99c01 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -@@ -128,7 +128,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB - if (this.variant == null) { - this.variant = 0; - } -- this.variant = CraftTropicalFish.getData(color, this.getPatternColor(), this.getPattern()); -+ this.variant = CraftTropicalFish.getData(color, this.getBodyColor(), this.getPattern()); // Paper - properly set tropical fish pattern color without mutating body color - } - - @Override -diff --git a/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..68a557cedbffb41f27ba21096e2ae5eebbf13f5c ---- /dev/null -+++ b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java -@@ -0,0 +1,41 @@ -+package io.papermc.paper.inventory; -+ -+import org.bukkit.DyeColor; -+import org.bukkit.Material; -+import org.bukkit.entity.TropicalFish; -+import org.bukkit.inventory.ItemStack; -+import org.bukkit.inventory.meta.TropicalFishBucketMeta; -+import org.bukkit.support.environment.AllFeatures; -+import org.junit.jupiter.api.Assertions; -+import org.junit.jupiter.api.Test; -+ -+@AllFeatures -+public class CraftMetaTropicalFishBucketTest { -+ -+ @Test -+ public void testAllCombinations() { -+ final var rawMeta = new ItemStack(Material.TROPICAL_FISH_BUCKET).getItemMeta(); -+ Assertions.assertTrue(rawMeta instanceof TropicalFishBucketMeta, "Meta was not a tropical fish bucket"); -+ -+ final var meta = (TropicalFishBucketMeta) rawMeta; -+ -+ for (final var bodyColor : DyeColor.values()) { -+ for (final var pattern : TropicalFish.Pattern.values()) { -+ for (final var patternColor : DyeColor.values()) { -+ meta.setBodyColor(bodyColor); -+ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post body color!"); -+ -+ meta.setPattern(pattern); -+ Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern!"); -+ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern!"); -+ -+ meta.setPatternColor(patternColor); -+ Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern color!"); -+ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern color!"); -+ Assertions.assertEquals(patternColor, meta.getPatternColor(), "Pattern color did not match post pattern color!"); -+ } -+ } -+ } -+ } -+ -+} diff --git a/patches/server/0610-Ensure-valid-vehicle-status.patch b/patches/server/0610-Ensure-valid-vehicle-status.patch deleted file mode 100644 index c4359b2054..0000000000 --- a/patches/server/0610-Ensure-valid-vehicle-status.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Tue, 28 Sep 2021 09:47:47 +0200 -Subject: [PATCH] Ensure valid vehicle status - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index d2fbbdbb451d6c54d847b4ba125397ad41c4f7b4..f72ab5e4e743cb0758ebca28e81f97c143c91b42 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -698,7 +698,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } - } - -- if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger()) { -+ if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger() && !entity.isRemoved()) { // Paper - Ensure valid vehicle status - // CraftBukkit end - CompoundTag nbttagcompound1 = new CompoundTag(); - CompoundTag nbttagcompound2 = new CompoundTag(); diff --git a/patches/server/0610-Prevent-softlocked-end-exit-portal-generation.patch b/patches/server/0610-Prevent-softlocked-end-exit-portal-generation.patch new file mode 100644 index 0000000000..4c54f27f94 --- /dev/null +++ b/patches/server/0610-Prevent-softlocked-end-exit-portal-generation.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Mon, 30 Aug 2021 15:22:18 +0200 +Subject: [PATCH] Prevent softlocked end exit portal generation + + +diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +index 3d1a49d865e17a61ff74c6fe0efbd908447ee730..bc6426c04ac1fd19949d587d2b7061895db0893b 100644 +--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java ++++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +@@ -469,6 +469,11 @@ public class EndDragonFight { + } + } + ++ // Paper start - Prevent "softlocked" exit portal generation ++ if (this.portalLocation.getY() <= this.level.getMinY()) { ++ this.portalLocation = this.portalLocation.atY(this.level.getMinY() + 1); ++ } ++ // Paper end - Prevent "softlocked" exit portal generation + if (worldgenendtrophy.place(FeatureConfiguration.NONE, this.level, this.level.getChunkSource().getGenerator(), RandomSource.create(), this.portalLocation)) { + int i = Mth.positiveCeilDiv(4, 16); + diff --git a/patches/server/0611-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch b/patches/server/0611-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch new file mode 100644 index 0000000000..4fac0c1ab3 --- /dev/null +++ b/patches/server/0611-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Tue, 7 Sep 2021 21:29:38 +0100 +Subject: [PATCH] Fix CocaoDecorator causing a crash when trying to generate + without logs + + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java +index 1b59f530840a2a490e295f73db90ab266b27712f..f924f09aaf5d8fd643f86d826ab053dbe861369e 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java +@@ -26,6 +26,7 @@ public class CocoaDecorator extends TreeDecorator { + + @Override + public void place(TreeDecorator.Context generator) { ++ if (generator.logs().isEmpty()) return; // Paper - Fix crash when trying to generate without logs + RandomSource randomSource = generator.random(); + if (!(randomSource.nextFloat() >= this.probability)) { + List list = generator.logs(); diff --git a/patches/server/0611-Prevent-softlocked-end-exit-portal-generation.patch b/patches/server/0611-Prevent-softlocked-end-exit-portal-generation.patch deleted file mode 100644 index 4c54f27f94..0000000000 --- a/patches/server/0611-Prevent-softlocked-end-exit-portal-generation.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Mon, 30 Aug 2021 15:22:18 +0200 -Subject: [PATCH] Prevent softlocked end exit portal generation - - -diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -index 3d1a49d865e17a61ff74c6fe0efbd908447ee730..bc6426c04ac1fd19949d587d2b7061895db0893b 100644 ---- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -@@ -469,6 +469,11 @@ public class EndDragonFight { - } - } - -+ // Paper start - Prevent "softlocked" exit portal generation -+ if (this.portalLocation.getY() <= this.level.getMinY()) { -+ this.portalLocation = this.portalLocation.atY(this.level.getMinY() + 1); -+ } -+ // Paper end - Prevent "softlocked" exit portal generation - if (worldgenendtrophy.place(FeatureConfiguration.NONE, this.level, this.level.getChunkSource().getGenerator(), RandomSource.create(), this.portalLocation)) { - int i = Mth.positiveCeilDiv(4, 16); - diff --git a/patches/server/0612-Don-t-log-debug-logging-being-disabled.patch b/patches/server/0612-Don-t-log-debug-logging-being-disabled.patch new file mode 100644 index 0000000000..8e733b1cea --- /dev/null +++ b/patches/server/0612-Don-t-log-debug-logging-being-disabled.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Tue, 14 Sep 2021 16:24:45 +0200 +Subject: [PATCH] Don't log debug logging being disabled + + +diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java +index 85f3433860abd91a89961907940a807a8b190a46..4dbb109d0526afee99b9190fc256585121aac9b5 100644 +--- a/src/main/java/org/spigotmc/SpigotConfig.java ++++ b/src/main/java/org/spigotmc/SpigotConfig.java +@@ -381,7 +381,7 @@ public class SpigotConfig + Bukkit.getLogger().info( "Debug logging is enabled" ); + } else + { +- Bukkit.getLogger().info( "Debug logging is disabled" ); ++ // Bukkit.getLogger().info( "Debug logging is disabled" ); // Paper - Don't log if debug logging isn't enabled. + } + } + diff --git a/patches/server/0612-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch b/patches/server/0612-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch deleted file mode 100644 index 4fac0c1ab3..0000000000 --- a/patches/server/0612-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Tue, 7 Sep 2021 21:29:38 +0100 -Subject: [PATCH] Fix CocaoDecorator causing a crash when trying to generate - without logs - - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java -index 1b59f530840a2a490e295f73db90ab266b27712f..f924f09aaf5d8fd643f86d826ab053dbe861369e 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java -@@ -26,6 +26,7 @@ public class CocoaDecorator extends TreeDecorator { - - @Override - public void place(TreeDecorator.Context generator) { -+ if (generator.logs().isEmpty()) return; // Paper - Fix crash when trying to generate without logs - RandomSource randomSource = generator.random(); - if (!(randomSource.nextFloat() >= this.probability)) { - List list = generator.logs(); diff --git a/patches/server/0613-Don-t-log-debug-logging-being-disabled.patch b/patches/server/0613-Don-t-log-debug-logging-being-disabled.patch deleted file mode 100644 index 8e733b1cea..0000000000 --- a/patches/server/0613-Don-t-log-debug-logging-being-disabled.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Tue, 14 Sep 2021 16:24:45 +0200 -Subject: [PATCH] Don't log debug logging being disabled - - -diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java -index 85f3433860abd91a89961907940a807a8b190a46..4dbb109d0526afee99b9190fc256585121aac9b5 100644 ---- a/src/main/java/org/spigotmc/SpigotConfig.java -+++ b/src/main/java/org/spigotmc/SpigotConfig.java -@@ -381,7 +381,7 @@ public class SpigotConfig - Bukkit.getLogger().info( "Debug logging is enabled" ); - } else - { -- Bukkit.getLogger().info( "Debug logging is disabled" ); -+ // Bukkit.getLogger().info( "Debug logging is disabled" ); // Paper - Don't log if debug logging isn't enabled. - } - } - diff --git a/patches/server/0613-fix-various-menus-with-empty-level-accesses.patch b/patches/server/0613-fix-various-menus-with-empty-level-accesses.patch new file mode 100644 index 0000000000..efe5d1ddce --- /dev/null +++ b/patches/server/0613-fix-various-menus-with-empty-level-accesses.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 11 Jul 2021 12:52:56 -0700 +Subject: [PATCH] fix various menus with empty level accesses + + +diff --git a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java +index c96b04f045dda384cdee9254a1765ef97e5f7f03..85e336637db8643fc5aca1dba724c9b341cbf46f 100644 +--- a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java ++++ b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java +@@ -27,6 +27,12 @@ public interface ContainerLevelAccess { + public Optional evaluate(BiFunction getter) { + return Optional.empty(); + } ++ // Paper start - fix menus with empty level accesses ++ @Override ++ public org.bukkit.Location getLocation() { ++ return null; ++ } ++ // Paper end - fix menus with empty level accesses + }; + + static ContainerLevelAccess create(final Level world, final BlockPos pos) { diff --git a/patches/server/0614-Preserve-overstacked-loot.patch b/patches/server/0614-Preserve-overstacked-loot.patch new file mode 100644 index 0000000000..db50d2fd8a --- /dev/null +++ b/patches/server/0614-Preserve-overstacked-loot.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: lexikiq +Date: Mon, 21 Jun 2021 23:21:58 -0400 +Subject: [PATCH] Preserve overstacked loot + +Preserves overstacked items in loot tables, such as shulker box drops, to prevent the items +from being deleted (as they'd overflow past the bounds of the container)-- or worse, causing +chunk bans via the large amount of NBT created by unstacking the items. + +Fixes GH-5140 and GH-4748. + +diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java +index 4d4d413b8527e1a109276928611b8c857ad6f6aa..c2bded5094097f5615a2ddb0718942486ede93b5 100644 +--- a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java ++++ b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java +@@ -72,9 +72,10 @@ public class LootTable { + } + + public static Consumer createStackSplitter(ServerLevel world, Consumer consumer) { ++ boolean skipSplitter = world != null && !world.paperConfig().fixes.splitOverstackedLoot; // Paper - preserve overstacked items + return (itemstack) -> { + if (itemstack.isItemEnabled(world.enabledFeatures())) { +- if (itemstack.getCount() < itemstack.getMaxStackSize()) { ++ if (skipSplitter || itemstack.getCount() < itemstack.getMaxStackSize()) { // Paper - preserve overstacked items + consumer.accept(itemstack); + } else { + int i = itemstack.getCount(); diff --git a/patches/server/0614-fix-various-menus-with-empty-level-accesses.patch b/patches/server/0614-fix-various-menus-with-empty-level-accesses.patch deleted file mode 100644 index efe5d1ddce..0000000000 --- a/patches/server/0614-fix-various-menus-with-empty-level-accesses.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 11 Jul 2021 12:52:56 -0700 -Subject: [PATCH] fix various menus with empty level accesses - - -diff --git a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java -index c96b04f045dda384cdee9254a1765ef97e5f7f03..85e336637db8643fc5aca1dba724c9b341cbf46f 100644 ---- a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java -+++ b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java -@@ -27,6 +27,12 @@ public interface ContainerLevelAccess { - public Optional evaluate(BiFunction getter) { - return Optional.empty(); - } -+ // Paper start - fix menus with empty level accesses -+ @Override -+ public org.bukkit.Location getLocation() { -+ return null; -+ } -+ // Paper end - fix menus with empty level accesses - }; - - static ContainerLevelAccess create(final Level world, final BlockPos pos) { diff --git a/patches/server/0615-Preserve-overstacked-loot.patch b/patches/server/0615-Preserve-overstacked-loot.patch deleted file mode 100644 index db50d2fd8a..0000000000 --- a/patches/server/0615-Preserve-overstacked-loot.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: lexikiq -Date: Mon, 21 Jun 2021 23:21:58 -0400 -Subject: [PATCH] Preserve overstacked loot - -Preserves overstacked items in loot tables, such as shulker box drops, to prevent the items -from being deleted (as they'd overflow past the bounds of the container)-- or worse, causing -chunk bans via the large amount of NBT created by unstacking the items. - -Fixes GH-5140 and GH-4748. - -diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java -index 4d4d413b8527e1a109276928611b8c857ad6f6aa..c2bded5094097f5615a2ddb0718942486ede93b5 100644 ---- a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java -+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java -@@ -72,9 +72,10 @@ public class LootTable { - } - - public static Consumer createStackSplitter(ServerLevel world, Consumer consumer) { -+ boolean skipSplitter = world != null && !world.paperConfig().fixes.splitOverstackedLoot; // Paper - preserve overstacked items - return (itemstack) -> { - if (itemstack.isItemEnabled(world.enabledFeatures())) { -- if (itemstack.getCount() < itemstack.getMaxStackSize()) { -+ if (skipSplitter || itemstack.getCount() < itemstack.getMaxStackSize()) { // Paper - preserve overstacked items - consumer.accept(itemstack); - } else { - int i = itemstack.getCount(); diff --git a/patches/server/0615-Update-head-rotation-in-missing-places.patch b/patches/server/0615-Update-head-rotation-in-missing-places.patch new file mode 100644 index 0000000000..c1f529129d --- /dev/null +++ b/patches/server/0615-Update-head-rotation-in-missing-places.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Mon, 21 Jun 2021 21:55:23 -0400 +Subject: [PATCH] Update head rotation in missing places + +In certain areas the player's head rotation could be desynced when teleported/moved. +This is because bukkit uses a separate head rotation field for yaw. +This issue only applies to players. + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 11b3a0ece27cb2c01b908a9ac0c3d75f407f5ed0..7b01d1cd5db771a1b6ee030664070ffb75579a4c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1914,6 +1914,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.setXRot(Mth.clamp(pitch, -90.0F, 90.0F) % 360.0F); + this.yRotO = this.getYRot(); + this.xRotO = this.getXRot(); ++ this.setYHeadRot(yaw); // Paper - Update head rotation + } + + public void absMoveTo(double x, double y, double z) { +@@ -1956,6 +1957,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.setXRot(pitch); + this.setOldPosAndRot(); + this.reapplyPosition(); ++ this.setYHeadRot(yaw); // Paper - Update head rotation + } + + public final void setOldPosAndRot() { diff --git a/patches/server/0616-Update-head-rotation-in-missing-places.patch b/patches/server/0616-Update-head-rotation-in-missing-places.patch deleted file mode 100644 index c1f529129d..0000000000 --- a/patches/server/0616-Update-head-rotation-in-missing-places.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Mon, 21 Jun 2021 21:55:23 -0400 -Subject: [PATCH] Update head rotation in missing places - -In certain areas the player's head rotation could be desynced when teleported/moved. -This is because bukkit uses a separate head rotation field for yaw. -This issue only applies to players. - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 11b3a0ece27cb2c01b908a9ac0c3d75f407f5ed0..7b01d1cd5db771a1b6ee030664070ffb75579a4c 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1914,6 +1914,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.setXRot(Mth.clamp(pitch, -90.0F, 90.0F) % 360.0F); - this.yRotO = this.getYRot(); - this.xRotO = this.getXRot(); -+ this.setYHeadRot(yaw); // Paper - Update head rotation - } - - public void absMoveTo(double x, double y, double z) { -@@ -1956,6 +1957,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.setXRot(pitch); - this.setOldPosAndRot(); - this.reapplyPosition(); -+ this.setYHeadRot(yaw); // Paper - Update head rotation - } - - public final void setOldPosAndRot() { diff --git a/patches/server/0616-prevent-unintended-light-block-manipulation.patch b/patches/server/0616-prevent-unintended-light-block-manipulation.patch new file mode 100644 index 0000000000..b8ca205064 --- /dev/null +++ b/patches/server/0616-prevent-unintended-light-block-manipulation.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 13 Sep 2021 18:55:45 -0700 +Subject: [PATCH] prevent unintended light block manipulation + + +diff --git a/src/main/java/net/minecraft/world/level/block/LightBlock.java b/src/main/java/net/minecraft/world/level/block/LightBlock.java +index 6c3ca57a29d3c5ad1add1cf2f707b930dfc422ea..fec6bf38f080039436ba80d5528857ba4787bf4e 100644 +--- a/src/main/java/net/minecraft/world/level/block/LightBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LightBlock.java +@@ -50,6 +50,14 @@ public class LightBlock extends Block implements SimpleWaterloggedBlock { + builder.add(LEVEL, WATERLOGGED); + } + ++ // Paper start - prevent unintended light block manipulation ++ @Override ++ protected InteractionResult useItemOn(ItemStack stack, BlockState state, Level world, BlockPos pos, Player player, net.minecraft.world.InteractionHand hand, BlockHitResult hit) { ++ if (player.getItemInHand(hand).getItem() != Items.LIGHT || (world instanceof final net.minecraft.server.level.ServerLevel serverLevel && !player.mayInteract(serverLevel, pos)) || !player.mayUseItemAt(pos, hit.getDirection(), player.getItemInHand(hand))) { return net.minecraft.world.InteractionResult.PASS; } // Paper - Prevent unintended light block manipulation ++ return super.useItemOn(stack, state, world, pos, player, hand, hit); ++ } ++ // Paper end - prevent unintended light block manipulation ++ + @Override + protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { + if (!world.isClientSide && player.canUseGameMasterBlocks()) { diff --git a/patches/server/0617-Fix-CraftCriteria-defaults-map.patch b/patches/server/0617-Fix-CraftCriteria-defaults-map.patch new file mode 100644 index 0000000000..3e79bd7fb7 --- /dev/null +++ b/patches/server/0617-Fix-CraftCriteria-defaults-map.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 4 Oct 2021 22:31:51 -0700 +Subject: [PATCH] Fix CraftCriteria defaults map + + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java +index 441e2122f837712a21328eb7659cc9925ff9b6f8..8464531a4ee400834d25c23b1eb723f49be8689e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java +@@ -54,7 +54,7 @@ public final class CraftCriteria implements Criteria { + } + + static CraftCriteria getFromNMS(Objective objective) { +- return CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()); ++ return java.util.Objects.requireNonNullElseGet(CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()), () -> new CraftCriteria(objective.getCriteria())); // Paper + } + + public static CraftCriteria getFromBukkit(String name) { diff --git a/patches/server/0617-prevent-unintended-light-block-manipulation.patch b/patches/server/0617-prevent-unintended-light-block-manipulation.patch deleted file mode 100644 index b8ca205064..0000000000 --- a/patches/server/0617-prevent-unintended-light-block-manipulation.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 13 Sep 2021 18:55:45 -0700 -Subject: [PATCH] prevent unintended light block manipulation - - -diff --git a/src/main/java/net/minecraft/world/level/block/LightBlock.java b/src/main/java/net/minecraft/world/level/block/LightBlock.java -index 6c3ca57a29d3c5ad1add1cf2f707b930dfc422ea..fec6bf38f080039436ba80d5528857ba4787bf4e 100644 ---- a/src/main/java/net/minecraft/world/level/block/LightBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LightBlock.java -@@ -50,6 +50,14 @@ public class LightBlock extends Block implements SimpleWaterloggedBlock { - builder.add(LEVEL, WATERLOGGED); - } - -+ // Paper start - prevent unintended light block manipulation -+ @Override -+ protected InteractionResult useItemOn(ItemStack stack, BlockState state, Level world, BlockPos pos, Player player, net.minecraft.world.InteractionHand hand, BlockHitResult hit) { -+ if (player.getItemInHand(hand).getItem() != Items.LIGHT || (world instanceof final net.minecraft.server.level.ServerLevel serverLevel && !player.mayInteract(serverLevel, pos)) || !player.mayUseItemAt(pos, hit.getDirection(), player.getItemInHand(hand))) { return net.minecraft.world.InteractionResult.PASS; } // Paper - Prevent unintended light block manipulation -+ return super.useItemOn(stack, state, world, pos, player, hand, hit); -+ } -+ // Paper end - prevent unintended light block manipulation -+ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { - if (!world.isClientSide && player.canUseGameMasterBlocks()) { diff --git a/patches/server/0618-Fix-CraftCriteria-defaults-map.patch b/patches/server/0618-Fix-CraftCriteria-defaults-map.patch deleted file mode 100644 index 3e79bd7fb7..0000000000 --- a/patches/server/0618-Fix-CraftCriteria-defaults-map.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 4 Oct 2021 22:31:51 -0700 -Subject: [PATCH] Fix CraftCriteria defaults map - - -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java -index 441e2122f837712a21328eb7659cc9925ff9b6f8..8464531a4ee400834d25c23b1eb723f49be8689e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java -@@ -54,7 +54,7 @@ public final class CraftCriteria implements Criteria { - } - - static CraftCriteria getFromNMS(Objective objective) { -- return CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()); -+ return java.util.Objects.requireNonNullElseGet(CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()), () -> new CraftCriteria(objective.getCriteria())); // Paper - } - - public static CraftCriteria getFromBukkit(String name) { diff --git a/patches/server/0618-Fix-upstreams-block-state-factories.patch b/patches/server/0618-Fix-upstreams-block-state-factories.patch new file mode 100644 index 0000000000..93376fc4b1 --- /dev/null +++ b/patches/server/0618-Fix-upstreams-block-state-factories.patch @@ -0,0 +1,491 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 6 Oct 2021 20:50:48 -0700 +Subject: [PATCH] Fix upstreams block state factories + +Sometimes, blocks are changed and then logic is called before the associated +tile entity is removed. When this happens, the factories were relying on the +block at the position, not the tile entity. This change prioritizes using the +tile entity type to determine the block state factory and falls back on +the material type of the block at that location. + +== AT == +public net.minecraft.world.level.block.entity.BlockEntityType validBlocks + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +index 50413d317ce0282752c57535637f87d529f4c09f..09b85c4caa4ebaae1e8c2910b090c40a039a1be7 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -383,7 +383,7 @@ public abstract class BlockEntity { + // Paper end + if (this.level == null) return null; + org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ()); +- if (block.getType() == org.bukkit.Material.AIR) return null; ++ // if (block.getType() == org.bukkit.Material.AIR) return null; // Paper - actually get the tile entity if it still exists + org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper + if (state instanceof InventoryHolder) return (InventoryHolder) state; + return null; +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +index 80bd6e8a6dadb74356a9fa9aa394efbd31c49c37..fe7e3e0628783d8d1be9635b689da8a9cb46c5d7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +@@ -20,7 +20,7 @@ import org.bukkit.persistence.PersistentDataContainer; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-public class CraftBlockEntityState extends CraftBlockState implements TileState { ++public abstract class CraftBlockEntityState extends CraftBlockState implements TileState { // Paper - revert upstream's revert of the block state changes + + private final T tileEntity; + private final T snapshot; +@@ -196,14 +196,10 @@ public class CraftBlockEntityState extends CraftBlockStat + } + + @Override +- public CraftBlockEntityState copy() { +- return new CraftBlockEntityState<>(this, null); +- } ++ public abstract CraftBlockEntityState copy(); // Paper - make abstract + + @Override +- public CraftBlockEntityState copy(Location location) { +- return new CraftBlockEntityState<>(this, location); +- } ++ public abstract CraftBlockEntityState copy(Location location); // Paper - make abstract + + // Paper start + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +index 1a8dcde39a252a45046866349b848d79e1b13260..56453454cbd4b9e9270fc833f8ab38d5fa7a3763 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +@@ -22,6 +22,7 @@ import net.minecraft.world.level.block.entity.BeehiveBlockEntity; + import net.minecraft.world.level.block.entity.BellBlockEntity; + import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity; + import net.minecraft.world.level.block.entity.BlockEntity; ++import net.minecraft.world.level.block.entity.BlockEntityType; // Paper + import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; + import net.minecraft.world.level.block.entity.BrushableBlockEntity; + import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; +@@ -88,9 +89,9 @@ public final class CraftBlockStates { + private static class BlockEntityStateFactory> extends BlockStateFactory { + + private final BiFunction blockStateConstructor; +- private final BiFunction tileEntityConstructor; ++ private final BlockEntityType tileEntityConstructor; // Paper + +- protected BlockEntityStateFactory(Class blockStateType, BiFunction blockStateConstructor, BiFunction tileEntityConstructor) { ++ protected BlockEntityStateFactory(Class blockStateType, BiFunction blockStateConstructor, BlockEntityType tileEntityConstructor) { // Paper + super(blockStateType); + this.blockStateConstructor = blockStateConstructor; + this.tileEntityConstructor = tileEntityConstructor; +@@ -107,7 +108,7 @@ public final class CraftBlockStates { + } + + private T createTileEntity(BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData) { +- return this.tileEntityConstructor.apply(blockPosition, blockData); ++ return this.tileEntityConstructor.create(blockPosition, blockData); // Paper + } + + private B createBlockState(World world, T tileEntity) { +@@ -119,233 +120,66 @@ public final class CraftBlockStates { + private static final BlockStateFactory DEFAULT_FACTORY = new BlockStateFactory(CraftBlockState.class) { + @Override + public CraftBlockState createBlockState(World world, BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData, BlockEntity tileEntity) { +- // SPIGOT-6754, SPIGOT-6817: Restore previous behaviour for tile entities with removed blocks (loot generation post-destroy) +- if (tileEntity != null) { +- // block with unhandled TileEntity: +- return new CraftBlockEntityState<>(world, tileEntity); +- } ++ // Paper - revert upstream's revert of the block state changes. Block entities that have already had the block type set to AIR are still valid, upstream decided to ignore them + Preconditions.checkState(tileEntity == null, "Unexpected BlockState for %s", CraftBlockType.minecraftToBukkit(blockData.getBlock())); + return new CraftBlockState(world, blockPosition, blockData); + } + }; ++ // Paper start ++ private static final Map, BlockStateFactory> FACTORIES_BY_BLOCK_ENTITY_TYPE = new HashMap<>(); ++ private static void register(BlockEntityType type, BlockStateFactory factory) { ++ FACTORIES_BY_BLOCK_ENTITY_TYPE.put(type, factory); ++ } ++ // Paper end + + static { +- register( +- Arrays.asList( +- Material.ACACIA_SIGN, +- Material.ACACIA_WALL_SIGN, +- Material.BAMBOO_SIGN, +- Material.BAMBOO_WALL_SIGN, +- Material.BIRCH_SIGN, +- Material.BIRCH_WALL_SIGN, +- Material.CHERRY_SIGN, +- Material.CHERRY_WALL_SIGN, +- Material.CRIMSON_SIGN, +- Material.CRIMSON_WALL_SIGN, +- Material.DARK_OAK_SIGN, +- Material.DARK_OAK_WALL_SIGN, +- Material.JUNGLE_SIGN, +- Material.JUNGLE_WALL_SIGN, +- Material.MANGROVE_SIGN, +- Material.MANGROVE_WALL_SIGN, +- Material.OAK_SIGN, +- Material.OAK_WALL_SIGN, +- Material.PALE_OAK_SIGN, +- Material.PALE_OAK_WALL_SIGN, +- Material.SPRUCE_SIGN, +- Material.SPRUCE_WALL_SIGN, +- Material.WARPED_SIGN, +- Material.WARPED_WALL_SIGN +- ), CraftSign.class, CraftSign::new, SignBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.ACACIA_HANGING_SIGN, +- Material.ACACIA_WALL_HANGING_SIGN, +- Material.BAMBOO_HANGING_SIGN, +- Material.BAMBOO_WALL_HANGING_SIGN, +- Material.BIRCH_HANGING_SIGN, +- Material.BIRCH_WALL_HANGING_SIGN, +- Material.CHERRY_HANGING_SIGN, +- Material.CHERRY_WALL_HANGING_SIGN, +- Material.CRIMSON_HANGING_SIGN, +- Material.CRIMSON_WALL_HANGING_SIGN, +- Material.DARK_OAK_HANGING_SIGN, +- Material.DARK_OAK_WALL_HANGING_SIGN, +- Material.JUNGLE_HANGING_SIGN, +- Material.JUNGLE_WALL_HANGING_SIGN, +- Material.MANGROVE_HANGING_SIGN, +- Material.MANGROVE_WALL_HANGING_SIGN, +- Material.OAK_HANGING_SIGN, +- Material.OAK_WALL_HANGING_SIGN, +- Material.PALE_OAK_HANGING_SIGN, +- Material.PALE_OAK_WALL_HANGING_SIGN, +- Material.SPRUCE_HANGING_SIGN, +- Material.SPRUCE_WALL_HANGING_SIGN, +- Material.WARPED_HANGING_SIGN, +- Material.WARPED_WALL_HANGING_SIGN +- ), CraftHangingSign.class, CraftHangingSign::new, HangingSignBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.CREEPER_HEAD, +- Material.CREEPER_WALL_HEAD, +- Material.DRAGON_HEAD, +- Material.DRAGON_WALL_HEAD, +- Material.PIGLIN_HEAD, +- Material.PIGLIN_WALL_HEAD, +- Material.PLAYER_HEAD, +- Material.PLAYER_WALL_HEAD, +- Material.SKELETON_SKULL, +- Material.SKELETON_WALL_SKULL, +- Material.WITHER_SKELETON_SKULL, +- Material.WITHER_SKELETON_WALL_SKULL, +- Material.ZOMBIE_HEAD, +- Material.ZOMBIE_WALL_HEAD +- ), CraftSkull.class, CraftSkull::new, SkullBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.COMMAND_BLOCK, +- Material.REPEATING_COMMAND_BLOCK, +- Material.CHAIN_COMMAND_BLOCK +- ), CraftCommandBlock.class, CraftCommandBlock::new, CommandBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.BLACK_BANNER, +- Material.BLACK_WALL_BANNER, +- Material.BLUE_BANNER, +- Material.BLUE_WALL_BANNER, +- Material.BROWN_BANNER, +- Material.BROWN_WALL_BANNER, +- Material.CYAN_BANNER, +- Material.CYAN_WALL_BANNER, +- Material.GRAY_BANNER, +- Material.GRAY_WALL_BANNER, +- Material.GREEN_BANNER, +- Material.GREEN_WALL_BANNER, +- Material.LIGHT_BLUE_BANNER, +- Material.LIGHT_BLUE_WALL_BANNER, +- Material.LIGHT_GRAY_BANNER, +- Material.LIGHT_GRAY_WALL_BANNER, +- Material.LIME_BANNER, +- Material.LIME_WALL_BANNER, +- Material.MAGENTA_BANNER, +- Material.MAGENTA_WALL_BANNER, +- Material.ORANGE_BANNER, +- Material.ORANGE_WALL_BANNER, +- Material.PINK_BANNER, +- Material.PINK_WALL_BANNER, +- Material.PURPLE_BANNER, +- Material.PURPLE_WALL_BANNER, +- Material.RED_BANNER, +- Material.RED_WALL_BANNER, +- Material.WHITE_BANNER, +- Material.WHITE_WALL_BANNER, +- Material.YELLOW_BANNER, +- Material.YELLOW_WALL_BANNER +- ), CraftBanner.class, CraftBanner::new, BannerBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.SHULKER_BOX, +- Material.WHITE_SHULKER_BOX, +- Material.ORANGE_SHULKER_BOX, +- Material.MAGENTA_SHULKER_BOX, +- Material.LIGHT_BLUE_SHULKER_BOX, +- Material.YELLOW_SHULKER_BOX, +- Material.LIME_SHULKER_BOX, +- Material.PINK_SHULKER_BOX, +- Material.GRAY_SHULKER_BOX, +- Material.LIGHT_GRAY_SHULKER_BOX, +- Material.CYAN_SHULKER_BOX, +- Material.PURPLE_SHULKER_BOX, +- Material.BLUE_SHULKER_BOX, +- Material.BROWN_SHULKER_BOX, +- Material.GREEN_SHULKER_BOX, +- Material.RED_SHULKER_BOX, +- Material.BLACK_SHULKER_BOX +- ), CraftShulkerBox.class, CraftShulkerBox::new, ShulkerBoxBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.BLACK_BED, +- Material.BLUE_BED, +- Material.BROWN_BED, +- Material.CYAN_BED, +- Material.GRAY_BED, +- Material.GREEN_BED, +- Material.LIGHT_BLUE_BED, +- Material.LIGHT_GRAY_BED, +- Material.LIME_BED, +- Material.MAGENTA_BED, +- Material.ORANGE_BED, +- Material.PINK_BED, +- Material.PURPLE_BED, +- Material.RED_BED, +- Material.WHITE_BED, +- Material.YELLOW_BED +- ), CraftBed.class, CraftBed::new, BedBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.BEEHIVE, +- Material.BEE_NEST +- ), CraftBeehive.class, CraftBeehive::new, BeehiveBlockEntity::new +- ); +- +- register( +- Arrays.asList( +- Material.CAMPFIRE, +- Material.SOUL_CAMPFIRE +- ), CraftCampfire.class, CraftCampfire::new, CampfireBlockEntity::new +- ); +- +- register(Material.BARREL, CraftBarrel.class, CraftBarrel::new, BarrelBlockEntity::new); +- register(Material.BEACON, CraftBeacon.class, CraftBeacon::new, BeaconBlockEntity::new); +- register(Material.BELL, CraftBell.class, CraftBell::new, BellBlockEntity::new); +- register(Material.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new, BlastFurnaceBlockEntity::new); +- register(Material.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new, BrewingStandBlockEntity::new); +- register(Material.CHEST, CraftChest.class, CraftChest::new, ChestBlockEntity::new); +- register(Material.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new, ChiseledBookShelfBlockEntity::new); +- register(Material.COMPARATOR, CraftComparator.class, CraftComparator::new, ComparatorBlockEntity::new); +- register(Material.CONDUIT, CraftConduit.class, CraftConduit::new, ConduitBlockEntity::new); +- register(Material.CREAKING_HEART, CraftCreakingHeart.class, CraftCreakingHeart::new, CreakingHeartBlockEntity::new); +- register(Material.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new, DaylightDetectorBlockEntity::new); +- register(Material.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new, DecoratedPotBlockEntity::new); +- register(Material.DISPENSER, CraftDispenser.class, CraftDispenser::new, DispenserBlockEntity::new); +- register(Material.DROPPER, CraftDropper.class, CraftDropper::new, DropperBlockEntity::new); +- register(Material.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new, EnchantingTableBlockEntity::new); +- register(Material.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new, EnderChestBlockEntity::new); +- register(Material.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new, TheEndGatewayBlockEntity::new); +- register(Material.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new, TheEndPortalBlockEntity::new); +- register(Material.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new, FurnaceBlockEntity::new); +- register(Material.HOPPER, CraftHopper.class, CraftHopper::new, HopperBlockEntity::new); +- register(Material.JIGSAW, CraftJigsaw.class, CraftJigsaw::new, JigsawBlockEntity::new); +- register(Material.JUKEBOX, CraftJukebox.class, CraftJukebox::new, JukeboxBlockEntity::new); +- register(Material.LECTERN, CraftLectern.class, CraftLectern::new, LecternBlockEntity::new); +- register(Material.MOVING_PISTON, CraftMovingPiston.class, CraftMovingPiston::new, PistonMovingBlockEntity::new); +- register(Material.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new, SculkCatalystBlockEntity::new); +- register(Material.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new, CalibratedSculkSensorBlockEntity::new); +- register(Material.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new, SculkSensorBlockEntity::new); +- register(Material.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new, SculkShriekerBlockEntity::new); +- register(Material.SMOKER, CraftSmoker.class, CraftSmoker::new, SmokerBlockEntity::new); +- register(Material.SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new, SpawnerBlockEntity::new); +- register(Material.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new, StructureBlockEntity::new); +- register(Material.SUSPICIOUS_SAND, CraftSuspiciousSand.class, CraftSuspiciousSand::new, BrushableBlockEntity::new); +- register(Material.SUSPICIOUS_GRAVEL, CraftBrushableBlock.class, CraftBrushableBlock::new, BrushableBlockEntity::new); +- register(Material.TRAPPED_CHEST, CraftChest.class, CraftChest::new, TrappedChestBlockEntity::new); +- register(Material.CRAFTER, CraftCrafter.class, CraftCrafter::new, CrafterBlockEntity::new); +- register(Material.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new, TrialSpawnerBlockEntity::new); +- register(Material.VAULT, CraftVault.class, CraftVault::new, VaultBlockEntity::new); ++ // Paper start - simplify ++ register(BlockEntityType.SIGN, CraftSign.class, CraftSign::new); ++ register(BlockEntityType.HANGING_SIGN, CraftHangingSign.class, CraftHangingSign::new); ++ register(BlockEntityType.SKULL, CraftSkull.class, CraftSkull::new); ++ register(BlockEntityType.COMMAND_BLOCK, CraftCommandBlock.class, CraftCommandBlock::new); ++ register(BlockEntityType.BANNER, CraftBanner.class, CraftBanner::new); ++ register(BlockEntityType.SHULKER_BOX, CraftShulkerBox.class, CraftShulkerBox::new); ++ register(BlockEntityType.BED, CraftBed.class, CraftBed::new); ++ register(BlockEntityType.BEEHIVE, CraftBeehive.class, CraftBeehive::new); ++ register(BlockEntityType.CAMPFIRE, CraftCampfire.class, CraftCampfire::new); ++ register(BlockEntityType.BARREL, CraftBarrel.class, CraftBarrel::new); ++ register(BlockEntityType.BEACON, CraftBeacon.class, CraftBeacon::new); ++ register(BlockEntityType.BELL, CraftBell.class, CraftBell::new); ++ register(BlockEntityType.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new); ++ register(BlockEntityType.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new); ++ register(BlockEntityType.CHEST, CraftChest.class, CraftChest::new); ++ register(BlockEntityType.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new); ++ register(BlockEntityType.COMPARATOR, CraftComparator.class, CraftComparator::new); ++ register(BlockEntityType.CONDUIT, CraftConduit.class, CraftConduit::new); ++ register(BlockEntityType.CREAKING_HEART, CraftCreakingHeart.class, CraftCreakingHeart::new); ++ register(BlockEntityType.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new); ++ register(BlockEntityType.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new); ++ register(BlockEntityType.DISPENSER, CraftDispenser.class, CraftDispenser::new); ++ register(BlockEntityType.DROPPER, CraftDropper.class, CraftDropper::new); ++ register(BlockEntityType.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new); ++ register(BlockEntityType.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new); ++ register(BlockEntityType.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new); ++ register(BlockEntityType.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new); ++ register(BlockEntityType.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new); ++ register(BlockEntityType.HOPPER, CraftHopper.class, CraftHopper::new); ++ register(BlockEntityType.JIGSAW, CraftJigsaw.class, CraftJigsaw::new); ++ register(BlockEntityType.JUKEBOX, CraftJukebox.class, CraftJukebox::new); ++ register(BlockEntityType.LECTERN, CraftLectern.class, CraftLectern::new); ++ register(BlockEntityType.PISTON, CraftMovingPiston.class, CraftMovingPiston::new); ++ register(BlockEntityType.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new); ++ register(BlockEntityType.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new); ++ register(BlockEntityType.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new); ++ register(BlockEntityType.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new); ++ register(BlockEntityType.SMOKER, CraftSmoker.class, CraftSmoker::new); ++ register(BlockEntityType.MOB_SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new); ++ register(BlockEntityType.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new); ++ register(BlockEntityType.BRUSHABLE_BLOCK, CraftBrushableBlock.class, CraftBrushableBlock::new); // note: spigot still uses CraftSuspiciousSand impl for that block type ++ register(BlockEntityType.TRAPPED_CHEST, CraftChest.class, CraftChest::new); ++ register(BlockEntityType.CRAFTER, CraftCrafter.class, CraftCrafter::new); ++ register(BlockEntityType.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new); ++ register(BlockEntityType.VAULT, CraftVault.class, CraftVault::new); ++ // Paper end + } + + private static void register(Material blockType, BlockStateFactory factory) { +@@ -353,30 +187,33 @@ public final class CraftBlockStates { + } + + private static > void register( +- Material blockType, ++ net.minecraft.world.level.block.entity.BlockEntityType blockEntityType, // Paper + Class blockStateType, +- BiFunction blockStateConstructor, +- BiFunction tileEntityConstructor ++ BiFunction blockStateConstructor // Paper + ) { +- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor); +- } +- +- private static > void register( +- List blockTypes, +- Class blockStateType, +- BiFunction blockStateConstructor, +- BiFunction tileEntityConstructor +- ) { +- BlockStateFactory factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, tileEntityConstructor); +- for (Material blockType : blockTypes) { +- CraftBlockStates.register(blockType, factory); ++ // Paper start ++ BlockStateFactory factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, blockEntityType); // Paper ++ for (net.minecraft.world.level.block.Block block : blockEntityType.validBlocks) { ++ CraftBlockStates.register(CraftBlockType.minecraftToBukkit(block), factory); + } ++ CraftBlockStates.register(blockEntityType, factory); ++ // Paper end + } + + private static BlockStateFactory getFactory(Material material) { + return CraftBlockStates.FACTORIES.getOrDefault(material, CraftBlockStates.DEFAULT_FACTORY); + } + ++ // Paper start ++ private static BlockStateFactory getFactory(Material material, BlockEntityType type) { ++ if (type != null) { ++ return CraftBlockStates.FACTORIES_BY_BLOCK_ENTITY_TYPE.getOrDefault(type, getFactory(material)); ++ } else { ++ return getFactory(material); ++ } ++ } ++ // Paper end ++ + public static Class getBlockStateType(Material material) { + Preconditions.checkNotNull(material, "material is null"); + return CraftBlockStates.getFactory(material).blockStateType; +@@ -392,6 +229,13 @@ public final class CraftBlockStates { + return null; + } + ++ // Paper start ++ public static Class getBlockStateType(BlockEntityType blockEntityType) { ++ Preconditions.checkNotNull(blockEntityType, "blockEntityType is null"); ++ return CraftBlockStates.getFactory(null, blockEntityType).blockStateType; ++ } ++ // Paper end ++ + public static BlockState getBlockState(Block block) { + // Paper start + return CraftBlockStates.getBlockState(block, true); +@@ -459,7 +303,7 @@ public final class CraftBlockStates { + if (world != null && tileEntity == null && CraftBlockStates.isTileEntityOptional(material)) { + factory = CraftBlockStates.DEFAULT_FACTORY; + } else { +- factory = CraftBlockStates.getFactory(material); ++ factory = CraftBlockStates.getFactory(material, tileEntity != null ? tileEntity.getType() : null); // Paper + } + return factory.createBlockState(world, blockPosition, blockData, tileEntity); + } +@@ -478,6 +322,14 @@ public final class CraftBlockStates { + return new CraftBlockState(CraftBlock.at(world, pos), flag); + } + ++ // Paper start ++ @Nullable ++ public static BlockEntityType getBlockEntityType(final Material material) { ++ final BlockStateFactory factory = org.bukkit.craftbukkit.block.CraftBlockStates.FACTORIES.get(material); ++ return factory instanceof final BlockEntityStateFactory blockEntityStateFactory ? blockEntityStateFactory.tileEntityConstructor : null; ++ } ++ // Paper end ++ + private CraftBlockStates() { + } + } +diff --git a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java +index c032daa6957df2ad8b621379e415ad925f5cc162..a9810c88e05ebc1af60c051faa45e50ee183924f 100644 +--- a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java +@@ -7,6 +7,7 @@ import net.minecraft.core.registries.BuiltInRegistries; + import net.minecraft.world.level.block.Block; + import net.minecraft.world.level.block.EntityBlock; + import net.minecraft.world.level.block.entity.BlockEntity; ++import net.minecraft.world.level.block.entity.BlockEntityType; + import org.bukkit.Material; + import org.bukkit.support.environment.AllFeatures; + import org.junit.jupiter.api.Test; +@@ -42,4 +43,13 @@ public class BlockStateTest { + } + } + } ++ ++ // Paper start ++ @Test ++ public void testBlockEntityTypes() { ++ for (var blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { ++ org.junit.jupiter.api.Assertions.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType)); ++ } ++ } ++ // Paper end + } diff --git a/patches/server/0619-Configurable-feature-seeds.patch b/patches/server/0619-Configurable-feature-seeds.patch new file mode 100644 index 0000000000..b374cbddbf --- /dev/null +++ b/patches/server/0619-Configurable-feature-seeds.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Tue, 31 Aug 2021 17:05:27 +0200 +Subject: [PATCH] Configurable feature seeds + +Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> + +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +index e3c5a49611d584fbd19a44da5aa78ff6d7c43881..fc8e3edd9734fa7b69f0fc6b4eefd8a704e451cf 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -436,7 +436,14 @@ public abstract class ChunkGenerator { + return (String) optional.orElseGet(placedfeature::toString); + }; + +- seededrandom.setFeatureSeed(i, l1, l); ++ // Paper start - Configurable feature seeds; change populationSeed used in random ++ long featurePopulationSeed = i; ++ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedfeature.feature()); ++ if (configFeatureSeed != -1) { ++ featurePopulationSeed = seededrandom.setDecorationSeed(configFeatureSeed, blockposition.getX(), blockposition.getZ()); // See seededrandom.setDecorationSeed from above ++ } ++ seededrandom.setFeatureSeed(featurePopulationSeed, l1, l); ++ // Paper end - Configurable feature seeds + + try { + generatoraccessseed.setCurrentlyGenerating(supplier1); diff --git a/patches/server/0619-Fix-upstreams-block-state-factories.patch b/patches/server/0619-Fix-upstreams-block-state-factories.patch deleted file mode 100644 index bca94bd673..0000000000 --- a/patches/server/0619-Fix-upstreams-block-state-factories.patch +++ /dev/null @@ -1,491 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 6 Oct 2021 20:50:48 -0700 -Subject: [PATCH] Fix upstreams block state factories - -Sometimes, blocks are changed and then logic is called before the associated -tile entity is removed. When this happens, the factories were relying on the -block at the position, not the tile entity. This change prioritizes using the -tile entity type to determine the block state factory and falls back on -the material type of the block at that location. - -== AT == -public net.minecraft.world.level.block.entity.BlockEntityType validBlocks - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 46a831f86b512f4228be8ccee40fb0f7bf0d6df6..3de01d92e1c97e287a1f0d1f8de81b4f530b4a84 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -388,7 +388,7 @@ public abstract class BlockEntity { - // Paper end - if (this.level == null) return null; - org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ()); -- if (block.getType() == org.bukkit.Material.AIR) return null; -+ // if (block.getType() == org.bukkit.Material.AIR) return null; // Paper - actually get the tile entity if it still exists - org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper - if (state instanceof InventoryHolder) return (InventoryHolder) state; - return null; -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -index 80bd6e8a6dadb74356a9fa9aa394efbd31c49c37..fe7e3e0628783d8d1be9635b689da8a9cb46c5d7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -@@ -20,7 +20,7 @@ import org.bukkit.persistence.PersistentDataContainer; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - --public class CraftBlockEntityState extends CraftBlockState implements TileState { -+public abstract class CraftBlockEntityState extends CraftBlockState implements TileState { // Paper - revert upstream's revert of the block state changes - - private final T tileEntity; - private final T snapshot; -@@ -196,14 +196,10 @@ public class CraftBlockEntityState extends CraftBlockStat - } - - @Override -- public CraftBlockEntityState copy() { -- return new CraftBlockEntityState<>(this, null); -- } -+ public abstract CraftBlockEntityState copy(); // Paper - make abstract - - @Override -- public CraftBlockEntityState copy(Location location) { -- return new CraftBlockEntityState<>(this, location); -- } -+ public abstract CraftBlockEntityState copy(Location location); // Paper - make abstract - - // Paper start - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java -index 1a8dcde39a252a45046866349b848d79e1b13260..56453454cbd4b9e9270fc833f8ab38d5fa7a3763 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java -@@ -22,6 +22,7 @@ import net.minecraft.world.level.block.entity.BeehiveBlockEntity; - import net.minecraft.world.level.block.entity.BellBlockEntity; - import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity; - import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.entity.BlockEntityType; // Paper - import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; - import net.minecraft.world.level.block.entity.BrushableBlockEntity; - import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; -@@ -88,9 +89,9 @@ public final class CraftBlockStates { - private static class BlockEntityStateFactory> extends BlockStateFactory { - - private final BiFunction blockStateConstructor; -- private final BiFunction tileEntityConstructor; -+ private final BlockEntityType tileEntityConstructor; // Paper - -- protected BlockEntityStateFactory(Class blockStateType, BiFunction blockStateConstructor, BiFunction tileEntityConstructor) { -+ protected BlockEntityStateFactory(Class blockStateType, BiFunction blockStateConstructor, BlockEntityType tileEntityConstructor) { // Paper - super(blockStateType); - this.blockStateConstructor = blockStateConstructor; - this.tileEntityConstructor = tileEntityConstructor; -@@ -107,7 +108,7 @@ public final class CraftBlockStates { - } - - private T createTileEntity(BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData) { -- return this.tileEntityConstructor.apply(blockPosition, blockData); -+ return this.tileEntityConstructor.create(blockPosition, blockData); // Paper - } - - private B createBlockState(World world, T tileEntity) { -@@ -119,233 +120,66 @@ public final class CraftBlockStates { - private static final BlockStateFactory DEFAULT_FACTORY = new BlockStateFactory(CraftBlockState.class) { - @Override - public CraftBlockState createBlockState(World world, BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData, BlockEntity tileEntity) { -- // SPIGOT-6754, SPIGOT-6817: Restore previous behaviour for tile entities with removed blocks (loot generation post-destroy) -- if (tileEntity != null) { -- // block with unhandled TileEntity: -- return new CraftBlockEntityState<>(world, tileEntity); -- } -+ // Paper - revert upstream's revert of the block state changes. Block entities that have already had the block type set to AIR are still valid, upstream decided to ignore them - Preconditions.checkState(tileEntity == null, "Unexpected BlockState for %s", CraftBlockType.minecraftToBukkit(blockData.getBlock())); - return new CraftBlockState(world, blockPosition, blockData); - } - }; -+ // Paper start -+ private static final Map, BlockStateFactory> FACTORIES_BY_BLOCK_ENTITY_TYPE = new HashMap<>(); -+ private static void register(BlockEntityType type, BlockStateFactory factory) { -+ FACTORIES_BY_BLOCK_ENTITY_TYPE.put(type, factory); -+ } -+ // Paper end - - static { -- register( -- Arrays.asList( -- Material.ACACIA_SIGN, -- Material.ACACIA_WALL_SIGN, -- Material.BAMBOO_SIGN, -- Material.BAMBOO_WALL_SIGN, -- Material.BIRCH_SIGN, -- Material.BIRCH_WALL_SIGN, -- Material.CHERRY_SIGN, -- Material.CHERRY_WALL_SIGN, -- Material.CRIMSON_SIGN, -- Material.CRIMSON_WALL_SIGN, -- Material.DARK_OAK_SIGN, -- Material.DARK_OAK_WALL_SIGN, -- Material.JUNGLE_SIGN, -- Material.JUNGLE_WALL_SIGN, -- Material.MANGROVE_SIGN, -- Material.MANGROVE_WALL_SIGN, -- Material.OAK_SIGN, -- Material.OAK_WALL_SIGN, -- Material.PALE_OAK_SIGN, -- Material.PALE_OAK_WALL_SIGN, -- Material.SPRUCE_SIGN, -- Material.SPRUCE_WALL_SIGN, -- Material.WARPED_SIGN, -- Material.WARPED_WALL_SIGN -- ), CraftSign.class, CraftSign::new, SignBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.ACACIA_HANGING_SIGN, -- Material.ACACIA_WALL_HANGING_SIGN, -- Material.BAMBOO_HANGING_SIGN, -- Material.BAMBOO_WALL_HANGING_SIGN, -- Material.BIRCH_HANGING_SIGN, -- Material.BIRCH_WALL_HANGING_SIGN, -- Material.CHERRY_HANGING_SIGN, -- Material.CHERRY_WALL_HANGING_SIGN, -- Material.CRIMSON_HANGING_SIGN, -- Material.CRIMSON_WALL_HANGING_SIGN, -- Material.DARK_OAK_HANGING_SIGN, -- Material.DARK_OAK_WALL_HANGING_SIGN, -- Material.JUNGLE_HANGING_SIGN, -- Material.JUNGLE_WALL_HANGING_SIGN, -- Material.MANGROVE_HANGING_SIGN, -- Material.MANGROVE_WALL_HANGING_SIGN, -- Material.OAK_HANGING_SIGN, -- Material.OAK_WALL_HANGING_SIGN, -- Material.PALE_OAK_HANGING_SIGN, -- Material.PALE_OAK_WALL_HANGING_SIGN, -- Material.SPRUCE_HANGING_SIGN, -- Material.SPRUCE_WALL_HANGING_SIGN, -- Material.WARPED_HANGING_SIGN, -- Material.WARPED_WALL_HANGING_SIGN -- ), CraftHangingSign.class, CraftHangingSign::new, HangingSignBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.CREEPER_HEAD, -- Material.CREEPER_WALL_HEAD, -- Material.DRAGON_HEAD, -- Material.DRAGON_WALL_HEAD, -- Material.PIGLIN_HEAD, -- Material.PIGLIN_WALL_HEAD, -- Material.PLAYER_HEAD, -- Material.PLAYER_WALL_HEAD, -- Material.SKELETON_SKULL, -- Material.SKELETON_WALL_SKULL, -- Material.WITHER_SKELETON_SKULL, -- Material.WITHER_SKELETON_WALL_SKULL, -- Material.ZOMBIE_HEAD, -- Material.ZOMBIE_WALL_HEAD -- ), CraftSkull.class, CraftSkull::new, SkullBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.COMMAND_BLOCK, -- Material.REPEATING_COMMAND_BLOCK, -- Material.CHAIN_COMMAND_BLOCK -- ), CraftCommandBlock.class, CraftCommandBlock::new, CommandBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.BLACK_BANNER, -- Material.BLACK_WALL_BANNER, -- Material.BLUE_BANNER, -- Material.BLUE_WALL_BANNER, -- Material.BROWN_BANNER, -- Material.BROWN_WALL_BANNER, -- Material.CYAN_BANNER, -- Material.CYAN_WALL_BANNER, -- Material.GRAY_BANNER, -- Material.GRAY_WALL_BANNER, -- Material.GREEN_BANNER, -- Material.GREEN_WALL_BANNER, -- Material.LIGHT_BLUE_BANNER, -- Material.LIGHT_BLUE_WALL_BANNER, -- Material.LIGHT_GRAY_BANNER, -- Material.LIGHT_GRAY_WALL_BANNER, -- Material.LIME_BANNER, -- Material.LIME_WALL_BANNER, -- Material.MAGENTA_BANNER, -- Material.MAGENTA_WALL_BANNER, -- Material.ORANGE_BANNER, -- Material.ORANGE_WALL_BANNER, -- Material.PINK_BANNER, -- Material.PINK_WALL_BANNER, -- Material.PURPLE_BANNER, -- Material.PURPLE_WALL_BANNER, -- Material.RED_BANNER, -- Material.RED_WALL_BANNER, -- Material.WHITE_BANNER, -- Material.WHITE_WALL_BANNER, -- Material.YELLOW_BANNER, -- Material.YELLOW_WALL_BANNER -- ), CraftBanner.class, CraftBanner::new, BannerBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.SHULKER_BOX, -- Material.WHITE_SHULKER_BOX, -- Material.ORANGE_SHULKER_BOX, -- Material.MAGENTA_SHULKER_BOX, -- Material.LIGHT_BLUE_SHULKER_BOX, -- Material.YELLOW_SHULKER_BOX, -- Material.LIME_SHULKER_BOX, -- Material.PINK_SHULKER_BOX, -- Material.GRAY_SHULKER_BOX, -- Material.LIGHT_GRAY_SHULKER_BOX, -- Material.CYAN_SHULKER_BOX, -- Material.PURPLE_SHULKER_BOX, -- Material.BLUE_SHULKER_BOX, -- Material.BROWN_SHULKER_BOX, -- Material.GREEN_SHULKER_BOX, -- Material.RED_SHULKER_BOX, -- Material.BLACK_SHULKER_BOX -- ), CraftShulkerBox.class, CraftShulkerBox::new, ShulkerBoxBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.BLACK_BED, -- Material.BLUE_BED, -- Material.BROWN_BED, -- Material.CYAN_BED, -- Material.GRAY_BED, -- Material.GREEN_BED, -- Material.LIGHT_BLUE_BED, -- Material.LIGHT_GRAY_BED, -- Material.LIME_BED, -- Material.MAGENTA_BED, -- Material.ORANGE_BED, -- Material.PINK_BED, -- Material.PURPLE_BED, -- Material.RED_BED, -- Material.WHITE_BED, -- Material.YELLOW_BED -- ), CraftBed.class, CraftBed::new, BedBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.BEEHIVE, -- Material.BEE_NEST -- ), CraftBeehive.class, CraftBeehive::new, BeehiveBlockEntity::new -- ); -- -- register( -- Arrays.asList( -- Material.CAMPFIRE, -- Material.SOUL_CAMPFIRE -- ), CraftCampfire.class, CraftCampfire::new, CampfireBlockEntity::new -- ); -- -- register(Material.BARREL, CraftBarrel.class, CraftBarrel::new, BarrelBlockEntity::new); -- register(Material.BEACON, CraftBeacon.class, CraftBeacon::new, BeaconBlockEntity::new); -- register(Material.BELL, CraftBell.class, CraftBell::new, BellBlockEntity::new); -- register(Material.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new, BlastFurnaceBlockEntity::new); -- register(Material.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new, BrewingStandBlockEntity::new); -- register(Material.CHEST, CraftChest.class, CraftChest::new, ChestBlockEntity::new); -- register(Material.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new, ChiseledBookShelfBlockEntity::new); -- register(Material.COMPARATOR, CraftComparator.class, CraftComparator::new, ComparatorBlockEntity::new); -- register(Material.CONDUIT, CraftConduit.class, CraftConduit::new, ConduitBlockEntity::new); -- register(Material.CREAKING_HEART, CraftCreakingHeart.class, CraftCreakingHeart::new, CreakingHeartBlockEntity::new); -- register(Material.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new, DaylightDetectorBlockEntity::new); -- register(Material.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new, DecoratedPotBlockEntity::new); -- register(Material.DISPENSER, CraftDispenser.class, CraftDispenser::new, DispenserBlockEntity::new); -- register(Material.DROPPER, CraftDropper.class, CraftDropper::new, DropperBlockEntity::new); -- register(Material.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new, EnchantingTableBlockEntity::new); -- register(Material.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new, EnderChestBlockEntity::new); -- register(Material.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new, TheEndGatewayBlockEntity::new); -- register(Material.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new, TheEndPortalBlockEntity::new); -- register(Material.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new, FurnaceBlockEntity::new); -- register(Material.HOPPER, CraftHopper.class, CraftHopper::new, HopperBlockEntity::new); -- register(Material.JIGSAW, CraftJigsaw.class, CraftJigsaw::new, JigsawBlockEntity::new); -- register(Material.JUKEBOX, CraftJukebox.class, CraftJukebox::new, JukeboxBlockEntity::new); -- register(Material.LECTERN, CraftLectern.class, CraftLectern::new, LecternBlockEntity::new); -- register(Material.MOVING_PISTON, CraftMovingPiston.class, CraftMovingPiston::new, PistonMovingBlockEntity::new); -- register(Material.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new, SculkCatalystBlockEntity::new); -- register(Material.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new, CalibratedSculkSensorBlockEntity::new); -- register(Material.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new, SculkSensorBlockEntity::new); -- register(Material.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new, SculkShriekerBlockEntity::new); -- register(Material.SMOKER, CraftSmoker.class, CraftSmoker::new, SmokerBlockEntity::new); -- register(Material.SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new, SpawnerBlockEntity::new); -- register(Material.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new, StructureBlockEntity::new); -- register(Material.SUSPICIOUS_SAND, CraftSuspiciousSand.class, CraftSuspiciousSand::new, BrushableBlockEntity::new); -- register(Material.SUSPICIOUS_GRAVEL, CraftBrushableBlock.class, CraftBrushableBlock::new, BrushableBlockEntity::new); -- register(Material.TRAPPED_CHEST, CraftChest.class, CraftChest::new, TrappedChestBlockEntity::new); -- register(Material.CRAFTER, CraftCrafter.class, CraftCrafter::new, CrafterBlockEntity::new); -- register(Material.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new, TrialSpawnerBlockEntity::new); -- register(Material.VAULT, CraftVault.class, CraftVault::new, VaultBlockEntity::new); -+ // Paper start - simplify -+ register(BlockEntityType.SIGN, CraftSign.class, CraftSign::new); -+ register(BlockEntityType.HANGING_SIGN, CraftHangingSign.class, CraftHangingSign::new); -+ register(BlockEntityType.SKULL, CraftSkull.class, CraftSkull::new); -+ register(BlockEntityType.COMMAND_BLOCK, CraftCommandBlock.class, CraftCommandBlock::new); -+ register(BlockEntityType.BANNER, CraftBanner.class, CraftBanner::new); -+ register(BlockEntityType.SHULKER_BOX, CraftShulkerBox.class, CraftShulkerBox::new); -+ register(BlockEntityType.BED, CraftBed.class, CraftBed::new); -+ register(BlockEntityType.BEEHIVE, CraftBeehive.class, CraftBeehive::new); -+ register(BlockEntityType.CAMPFIRE, CraftCampfire.class, CraftCampfire::new); -+ register(BlockEntityType.BARREL, CraftBarrel.class, CraftBarrel::new); -+ register(BlockEntityType.BEACON, CraftBeacon.class, CraftBeacon::new); -+ register(BlockEntityType.BELL, CraftBell.class, CraftBell::new); -+ register(BlockEntityType.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new); -+ register(BlockEntityType.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new); -+ register(BlockEntityType.CHEST, CraftChest.class, CraftChest::new); -+ register(BlockEntityType.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new); -+ register(BlockEntityType.COMPARATOR, CraftComparator.class, CraftComparator::new); -+ register(BlockEntityType.CONDUIT, CraftConduit.class, CraftConduit::new); -+ register(BlockEntityType.CREAKING_HEART, CraftCreakingHeart.class, CraftCreakingHeart::new); -+ register(BlockEntityType.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new); -+ register(BlockEntityType.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new); -+ register(BlockEntityType.DISPENSER, CraftDispenser.class, CraftDispenser::new); -+ register(BlockEntityType.DROPPER, CraftDropper.class, CraftDropper::new); -+ register(BlockEntityType.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new); -+ register(BlockEntityType.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new); -+ register(BlockEntityType.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new); -+ register(BlockEntityType.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new); -+ register(BlockEntityType.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new); -+ register(BlockEntityType.HOPPER, CraftHopper.class, CraftHopper::new); -+ register(BlockEntityType.JIGSAW, CraftJigsaw.class, CraftJigsaw::new); -+ register(BlockEntityType.JUKEBOX, CraftJukebox.class, CraftJukebox::new); -+ register(BlockEntityType.LECTERN, CraftLectern.class, CraftLectern::new); -+ register(BlockEntityType.PISTON, CraftMovingPiston.class, CraftMovingPiston::new); -+ register(BlockEntityType.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new); -+ register(BlockEntityType.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new); -+ register(BlockEntityType.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new); -+ register(BlockEntityType.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new); -+ register(BlockEntityType.SMOKER, CraftSmoker.class, CraftSmoker::new); -+ register(BlockEntityType.MOB_SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new); -+ register(BlockEntityType.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new); -+ register(BlockEntityType.BRUSHABLE_BLOCK, CraftBrushableBlock.class, CraftBrushableBlock::new); // note: spigot still uses CraftSuspiciousSand impl for that block type -+ register(BlockEntityType.TRAPPED_CHEST, CraftChest.class, CraftChest::new); -+ register(BlockEntityType.CRAFTER, CraftCrafter.class, CraftCrafter::new); -+ register(BlockEntityType.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new); -+ register(BlockEntityType.VAULT, CraftVault.class, CraftVault::new); -+ // Paper end - } - - private static void register(Material blockType, BlockStateFactory factory) { -@@ -353,30 +187,33 @@ public final class CraftBlockStates { - } - - private static > void register( -- Material blockType, -+ net.minecraft.world.level.block.entity.BlockEntityType blockEntityType, // Paper - Class blockStateType, -- BiFunction blockStateConstructor, -- BiFunction tileEntityConstructor -+ BiFunction blockStateConstructor // Paper - ) { -- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor); -- } -- -- private static > void register( -- List blockTypes, -- Class blockStateType, -- BiFunction blockStateConstructor, -- BiFunction tileEntityConstructor -- ) { -- BlockStateFactory factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, tileEntityConstructor); -- for (Material blockType : blockTypes) { -- CraftBlockStates.register(blockType, factory); -+ // Paper start -+ BlockStateFactory factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, blockEntityType); // Paper -+ for (net.minecraft.world.level.block.Block block : blockEntityType.validBlocks) { -+ CraftBlockStates.register(CraftBlockType.minecraftToBukkit(block), factory); - } -+ CraftBlockStates.register(blockEntityType, factory); -+ // Paper end - } - - private static BlockStateFactory getFactory(Material material) { - return CraftBlockStates.FACTORIES.getOrDefault(material, CraftBlockStates.DEFAULT_FACTORY); - } - -+ // Paper start -+ private static BlockStateFactory getFactory(Material material, BlockEntityType type) { -+ if (type != null) { -+ return CraftBlockStates.FACTORIES_BY_BLOCK_ENTITY_TYPE.getOrDefault(type, getFactory(material)); -+ } else { -+ return getFactory(material); -+ } -+ } -+ // Paper end -+ - public static Class getBlockStateType(Material material) { - Preconditions.checkNotNull(material, "material is null"); - return CraftBlockStates.getFactory(material).blockStateType; -@@ -392,6 +229,13 @@ public final class CraftBlockStates { - return null; - } - -+ // Paper start -+ public static Class getBlockStateType(BlockEntityType blockEntityType) { -+ Preconditions.checkNotNull(blockEntityType, "blockEntityType is null"); -+ return CraftBlockStates.getFactory(null, blockEntityType).blockStateType; -+ } -+ // Paper end -+ - public static BlockState getBlockState(Block block) { - // Paper start - return CraftBlockStates.getBlockState(block, true); -@@ -459,7 +303,7 @@ public final class CraftBlockStates { - if (world != null && tileEntity == null && CraftBlockStates.isTileEntityOptional(material)) { - factory = CraftBlockStates.DEFAULT_FACTORY; - } else { -- factory = CraftBlockStates.getFactory(material); -+ factory = CraftBlockStates.getFactory(material, tileEntity != null ? tileEntity.getType() : null); // Paper - } - return factory.createBlockState(world, blockPosition, blockData, tileEntity); - } -@@ -478,6 +322,14 @@ public final class CraftBlockStates { - return new CraftBlockState(CraftBlock.at(world, pos), flag); - } - -+ // Paper start -+ @Nullable -+ public static BlockEntityType getBlockEntityType(final Material material) { -+ final BlockStateFactory factory = org.bukkit.craftbukkit.block.CraftBlockStates.FACTORIES.get(material); -+ return factory instanceof final BlockEntityStateFactory blockEntityStateFactory ? blockEntityStateFactory.tileEntityConstructor : null; -+ } -+ // Paper end -+ - private CraftBlockStates() { - } - } -diff --git a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java -index c032daa6957df2ad8b621379e415ad925f5cc162..a9810c88e05ebc1af60c051faa45e50ee183924f 100644 ---- a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java -@@ -7,6 +7,7 @@ import net.minecraft.core.registries.BuiltInRegistries; - import net.minecraft.world.level.block.Block; - import net.minecraft.world.level.block.EntityBlock; - import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.entity.BlockEntityType; - import org.bukkit.Material; - import org.bukkit.support.environment.AllFeatures; - import org.junit.jupiter.api.Test; -@@ -42,4 +43,13 @@ public class BlockStateTest { - } - } - } -+ -+ // Paper start -+ @Test -+ public void testBlockEntityTypes() { -+ for (var blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { -+ org.junit.jupiter.api.Assertions.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType)); -+ } -+ } -+ // Paper end - } diff --git a/patches/server/0620-Add-root-admin-user-detection.patch b/patches/server/0620-Add-root-admin-user-detection.patch new file mode 100644 index 0000000000..df739cc33c --- /dev/null +++ b/patches/server/0620-Add-root-admin-user-detection.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: egg82 +Date: Sat, 11 Sep 2021 22:55:14 +0200 +Subject: [PATCH] Add root/admin user detection + +This patch detects whether or not the server is currently executing as a privileged user and spits out a warning. +The warning serves as a sort-of PSA for newer server admins who don't understand the risks of running as root. +We've seen plenty of bad/malicious plugins hit markets, and there's been a few close-calls with exploits in the past. +Hopefully this helps mitigate some potential damage to servers, even if it is just a warning. + +Co-authored-by: Noah van der Aa + +diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java +new file mode 100644 +index 0000000000000000000000000000000000000000..68098dfe716e93aafcca4d8d5b5a81d8648b3654 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.util; ++ ++import com.sun.security.auth.module.NTSystem; ++import com.sun.security.auth.module.UnixSystem; ++import java.util.Set; ++import org.apache.commons.lang.SystemUtils; ++ ++public class ServerEnvironment { ++ private static final boolean RUNNING_AS_ROOT_OR_ADMIN; ++ private static final String WINDOWS_HIGH_INTEGRITY_LEVEL = "S-1-16-12288"; ++ ++ static { ++ if (SystemUtils.IS_OS_WINDOWS) { ++ RUNNING_AS_ROOT_OR_ADMIN = Set.of(new NTSystem().getGroupIDs()).contains(WINDOWS_HIGH_INTEGRITY_LEVEL); ++ } else { ++ RUNNING_AS_ROOT_OR_ADMIN = new UnixSystem().getUid() == 0; ++ } ++ } ++ ++ public static boolean userIsRootOrAdmin() { ++ return RUNNING_AS_ROOT_OR_ADMIN; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 21d6f728d6ecd35a05933e9406a386c36135a456..ac7fc2497b860a143ef08498f5f477a373a29be7 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -193,6 +193,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); + } + ++ // Paper start - detect running as root ++ if (io.papermc.paper.util.ServerEnvironment.userIsRootOrAdmin()) { ++ DedicatedServer.LOGGER.warn("****************************"); ++ DedicatedServer.LOGGER.warn("YOU ARE RUNNING THIS SERVER AS AN ADMINISTRATIVE OR ROOT USER. THIS IS NOT ADVISED."); ++ DedicatedServer.LOGGER.warn("YOU ARE OPENING YOURSELF UP TO POTENTIAL RISKS WHEN DOING THIS."); ++ DedicatedServer.LOGGER.warn("FOR MORE INFORMATION, SEE https://madelinemiller.dev/blog/root-minecraft-server/"); ++ DedicatedServer.LOGGER.warn("****************************"); ++ } ++ // Paper end - detect running as root ++ + DedicatedServer.LOGGER.info("Loading properties"); + DedicatedServerProperties dedicatedserverproperties = this.settings.getProperties(); + diff --git a/patches/server/0620-Configurable-feature-seeds.patch b/patches/server/0620-Configurable-feature-seeds.patch deleted file mode 100644 index ffca9db1e2..0000000000 --- a/patches/server/0620-Configurable-feature-seeds.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Tue, 31 Aug 2021 17:05:27 +0200 -Subject: [PATCH] Configurable feature seeds - -Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> - -diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index 49028463ba47e760281545c2f7597e3db8d6c453..7620c72a4c243cbeea245203ce03a97cbfa7d922 100644 ---- a/src/main/java/co/aikar/timings/TimingsExport.java -+++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -286,7 +286,7 @@ public class TimingsExport extends Thread { - JSONObject object = new JSONObject(); - for (String key : config.getKeys(false)) { - String fullKey = (parentKey != null ? parentKey + "." + key : key); -- if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) { -+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld") || key.equals("feature-seeds")) { - continue; - } - final Object val = config.get(key); -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index e3c5a49611d584fbd19a44da5aa78ff6d7c43881..fc8e3edd9734fa7b69f0fc6b4eefd8a704e451cf 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -436,7 +436,14 @@ public abstract class ChunkGenerator { - return (String) optional.orElseGet(placedfeature::toString); - }; - -- seededrandom.setFeatureSeed(i, l1, l); -+ // Paper start - Configurable feature seeds; change populationSeed used in random -+ long featurePopulationSeed = i; -+ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedfeature.feature()); -+ if (configFeatureSeed != -1) { -+ featurePopulationSeed = seededrandom.setDecorationSeed(configFeatureSeed, blockposition.getX(), blockposition.getZ()); // See seededrandom.setDecorationSeed from above -+ } -+ seededrandom.setFeatureSeed(featurePopulationSeed, l1, l); -+ // Paper end - Configurable feature seeds - - try { - generatoraccessseed.setCurrentlyGenerating(supplier1); diff --git a/patches/server/0621-Add-root-admin-user-detection.patch b/patches/server/0621-Add-root-admin-user-detection.patch deleted file mode 100644 index af7475ee7f..0000000000 --- a/patches/server/0621-Add-root-admin-user-detection.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: egg82 -Date: Sat, 11 Sep 2021 22:55:14 +0200 -Subject: [PATCH] Add root/admin user detection - -This patch detects whether or not the server is currently executing as a privileged user and spits out a warning. -The warning serves as a sort-of PSA for newer server admins who don't understand the risks of running as root. -We've seen plenty of bad/malicious plugins hit markets, and there's been a few close-calls with exploits in the past. -Hopefully this helps mitigate some potential damage to servers, even if it is just a warning. - -Co-authored-by: Noah van der Aa - -diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java -new file mode 100644 -index 0000000000000000000000000000000000000000..68098dfe716e93aafcca4d8d5b5a81d8648b3654 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java -@@ -0,0 +1,23 @@ -+package io.papermc.paper.util; -+ -+import com.sun.security.auth.module.NTSystem; -+import com.sun.security.auth.module.UnixSystem; -+import java.util.Set; -+import org.apache.commons.lang.SystemUtils; -+ -+public class ServerEnvironment { -+ private static final boolean RUNNING_AS_ROOT_OR_ADMIN; -+ private static final String WINDOWS_HIGH_INTEGRITY_LEVEL = "S-1-16-12288"; -+ -+ static { -+ if (SystemUtils.IS_OS_WINDOWS) { -+ RUNNING_AS_ROOT_OR_ADMIN = Set.of(new NTSystem().getGroupIDs()).contains(WINDOWS_HIGH_INTEGRITY_LEVEL); -+ } else { -+ RUNNING_AS_ROOT_OR_ADMIN = new UnixSystem().getUid() == 0; -+ } -+ } -+ -+ public static boolean userIsRootOrAdmin() { -+ return RUNNING_AS_ROOT_OR_ADMIN; -+ } -+} -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index e30a5ad17d7ba8bcec8911a72281830c419b0288..3c3be48b29fcd38c5dea1bfca8d8690850aa948e 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -195,6 +195,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); - } - -+ // Paper start - detect running as root -+ if (io.papermc.paper.util.ServerEnvironment.userIsRootOrAdmin()) { -+ DedicatedServer.LOGGER.warn("****************************"); -+ DedicatedServer.LOGGER.warn("YOU ARE RUNNING THIS SERVER AS AN ADMINISTRATIVE OR ROOT USER. THIS IS NOT ADVISED."); -+ DedicatedServer.LOGGER.warn("YOU ARE OPENING YOURSELF UP TO POTENTIAL RISKS WHEN DOING THIS."); -+ DedicatedServer.LOGGER.warn("FOR MORE INFORMATION, SEE https://madelinemiller.dev/blog/root-minecraft-server/"); -+ DedicatedServer.LOGGER.warn("****************************"); -+ } -+ // Paper end - detect running as root -+ - DedicatedServer.LOGGER.info("Loading properties"); - DedicatedServerProperties dedicatedserverproperties = this.settings.getProperties(); - diff --git a/patches/server/0621-don-t-attempt-to-teleport-dead-entities.patch b/patches/server/0621-don-t-attempt-to-teleport-dead-entities.patch new file mode 100644 index 0000000000..89c8f26c2c --- /dev/null +++ b/patches/server/0621-don-t-attempt-to-teleport-dead-entities.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: sulu5890 +Date: Sun, 24 Oct 2021 22:48:14 -0500 +Subject: [PATCH] don't attempt to teleport dead entities + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 7b01d1cd5db771a1b6ee030664070ffb75579a4c..34cbb7c48535da774527b40f2e99f6f1d31c377d 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -713,7 +713,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + // CraftBukkit start + public void postTick() { + // No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle +- if (!(this instanceof ServerPlayer)) { ++ if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities + this.handlePortal(); + } + } diff --git a/patches/server/0622-Prevent-excessive-velocity-through-repeated-crits.patch b/patches/server/0622-Prevent-excessive-velocity-through-repeated-crits.patch new file mode 100644 index 0000000000..d7f8266ad6 --- /dev/null +++ b/patches/server/0622-Prevent-excessive-velocity-through-repeated-crits.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 25 Nov 2021 10:25:09 +0100 +Subject: [PATCH] Prevent excessive velocity through repeated crits + + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 564024738cc346abc024967c2d55f2553af3e660..8e0805bf6d330717f7555fbdb28d416295f8495a 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2863,17 +2863,29 @@ public abstract class LivingEntity extends Entity implements Attackable { + return this.hasEffect(MobEffects.JUMP) ? 0.1F * ((float) this.getEffect(MobEffects.JUMP).getAmplifier() + 1.0F) : 0.0F; + } + ++ protected long lastJumpTime = 0L; // Paper - Prevent excessive velocity through repeated crits + @VisibleForTesting + public void jumpFromGround() { + float f = this.getJumpPower(); + + if (f > 1.0E-5F) { + Vec3 vec3d = this.getDeltaMovement(); ++ // Paper start - Prevent excessive velocity through repeated crits ++ long time = System.nanoTime(); ++ boolean canCrit = true; ++ if (this instanceof net.minecraft.world.entity.player.Player) { ++ canCrit = false; ++ if (time - this.lastJumpTime > (long)(0.250e9)) { ++ this.lastJumpTime = time; ++ canCrit = true; ++ } ++ } ++ // Paper end - Prevent excessive velocity through repeated crits + + this.setDeltaMovement(vec3d.x, Math.max((double) f, vec3d.y), vec3d.z); + if (this.isSprinting()) { + float f1 = this.getYRot() * 0.017453292F; +- ++ if (canCrit) // Paper - Prevent excessive velocity through repeated crits + this.addDeltaMovement(new Vec3((double) (-Mth.sin(f1)) * 0.2D, 0.0D, (double) Mth.cos(f1) * 0.2D)); + } + diff --git a/patches/server/0622-don-t-attempt-to-teleport-dead-entities.patch b/patches/server/0622-don-t-attempt-to-teleport-dead-entities.patch deleted file mode 100644 index 89c8f26c2c..0000000000 --- a/patches/server/0622-don-t-attempt-to-teleport-dead-entities.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: sulu5890 -Date: Sun, 24 Oct 2021 22:48:14 -0500 -Subject: [PATCH] don't attempt to teleport dead entities - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 7b01d1cd5db771a1b6ee030664070ffb75579a4c..34cbb7c48535da774527b40f2e99f6f1d31c377d 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -713,7 +713,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - // CraftBukkit start - public void postTick() { - // No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle -- if (!(this instanceof ServerPlayer)) { -+ if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities - this.handlePortal(); - } - } diff --git a/patches/server/0623-Prevent-excessive-velocity-through-repeated-crits.patch b/patches/server/0623-Prevent-excessive-velocity-through-repeated-crits.patch deleted file mode 100644 index 9db70149e6..0000000000 --- a/patches/server/0623-Prevent-excessive-velocity-through-repeated-crits.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Thu, 25 Nov 2021 10:25:09 +0100 -Subject: [PATCH] Prevent excessive velocity through repeated crits - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 21f9fc5c3111dc126d0197a02bb61541fc422933..8c7ffa884f64a4263c9399953a7cfca6e35aab61 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2865,17 +2865,29 @@ public abstract class LivingEntity extends Entity implements Attackable { - return this.hasEffect(MobEffects.JUMP) ? 0.1F * ((float) this.getEffect(MobEffects.JUMP).getAmplifier() + 1.0F) : 0.0F; - } - -+ protected long lastJumpTime = 0L; // Paper - Prevent excessive velocity through repeated crits - @VisibleForTesting - public void jumpFromGround() { - float f = this.getJumpPower(); - - if (f > 1.0E-5F) { - Vec3 vec3d = this.getDeltaMovement(); -+ // Paper start - Prevent excessive velocity through repeated crits -+ long time = System.nanoTime(); -+ boolean canCrit = true; -+ if (this instanceof net.minecraft.world.entity.player.Player) { -+ canCrit = false; -+ if (time - this.lastJumpTime > (long)(0.250e9)) { -+ this.lastJumpTime = time; -+ canCrit = true; -+ } -+ } -+ // Paper end - Prevent excessive velocity through repeated crits - - this.setDeltaMovement(vec3d.x, Math.max((double) f, vec3d.y), vec3d.z); - if (this.isSprinting()) { - float f1 = this.getYRot() * 0.017453292F; -- -+ if (canCrit) // Paper - Prevent excessive velocity through repeated crits - this.addDeltaMovement(new Vec3((double) (-Mth.sin(f1)) * 0.2D, 0.0D, (double) Mth.cos(f1) * 0.2D)); - } - diff --git a/patches/server/0623-Remove-client-side-code-using-deprecated-for-removal.patch b/patches/server/0623-Remove-client-side-code-using-deprecated-for-removal.patch new file mode 100644 index 0000000000..1a9d2657f1 --- /dev/null +++ b/patches/server/0623-Remove-client-side-code-using-deprecated-for-removal.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Fri, 26 Nov 2021 15:09:58 -0800 +Subject: [PATCH] Remove client-side code using deprecated for removal + AccessController + +Fixes warnings on build + +diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java +index bf2833c92eca6491699b4a89410e4e46b5bbe4d1..57223285860f61119b6cf348aa78e59384a04e22 100644 +--- a/src/main/java/net/minecraft/Util.java ++++ b/src/main/java/net/minecraft/Util.java +@@ -1082,16 +1082,7 @@ public class Util { + } + + public void openUri(URI uri) { +- try { +- Process process = AccessController.doPrivileged( +- (PrivilegedExceptionAction)(() -> Runtime.getRuntime().exec(this.getOpenUriArguments(uri))) +- ); +- process.getInputStream().close(); +- process.getErrorStream().close(); +- process.getOutputStream().close(); +- } catch (IOException | PrivilegedActionException var3) { +- Util.LOGGER.error("Couldn't open location '{}'", uri, var3); +- } ++ throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code + } + + public void openFile(File file) { diff --git a/patches/server/0624-Fix-Spigot-growth-modifiers.patch b/patches/server/0624-Fix-Spigot-growth-modifiers.patch new file mode 100644 index 0000000000..6a24adf1c8 --- /dev/null +++ b/patches/server/0624-Fix-Spigot-growth-modifiers.patch @@ -0,0 +1,141 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Fri, 3 Dec 2021 17:09:24 -0800 +Subject: [PATCH] Fix Spigot growth modifiers + +Fixes kelp modifier changing growth for other crops +Also add growth modifiers for glow berries, mangrove propagules, +torchflower crops and pitcher plant crops +Also fix above-mentioned modifiers from having the reverse effect + +Co-authored-by: Jake Potrebic +Co-authored-by: Noah van der Aa +Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> + +diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java +index 437be546cf03b6af0856adabfeaf67bc33ff75d6..c4473c2a778116d48bc3e4796afd901f455070e6 100644 +--- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java +@@ -50,9 +50,18 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements CaveVines { + return to.setValue(BERRIES, from.getValue(BERRIES)); + } + ++ // Paper start - Fix Spigot growth modifiers ++ @Override ++ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) { ++ final boolean value = random.nextFloat() < (level != null ? (0.11F * (level.spigotConfig.glowBerryModifier / 100.0F)) : 0.11F); ++ return (BlockState) super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, value); ++ } ++ // Paper end - Fix Spigot growth modifiers ++ + @Override + protected BlockState getGrowIntoState(BlockState state, RandomSource random) { +- return super.getGrowIntoState(state, random).setValue(BERRIES, Boolean.valueOf(random.nextFloat() < 0.11F)); ++ // Paper start - Fix Spigot growth modifiers ++ return this.getGrowIntoState(state, random, null); + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java +index 79ebc37a779bf6cba66a34a7604f819e95fd86a2..1ada5ed825501666addacf527a513ab7bd4a3a58 100644 +--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java +@@ -91,6 +91,10 @@ public class CropBlock extends BushBlock implements BonemealableBlock { + modifier = world.spigotConfig.carrotModifier; + } else if (this == Blocks.POTATOES) { + modifier = world.spigotConfig.potatoModifier; ++ // Paper start - Fix Spigot growth modifiers ++ } else if (this == Blocks.TORCHFLOWER_CROP) { ++ modifier = world.spigotConfig.torchFlowerModifier; ++ // Paper end - Fix Spigot growth modifiers + } else { + modifier = world.spigotConfig.wheatModifier; + } +diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java +index c527f2d8f594d711d047a2a149efe37caaeb0308..9b424d7661fedf8ee1eb9f3167c62e563f04d4d1 100644 +--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java +@@ -60,12 +60,18 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements + BlockPos blockposition1 = pos.relative(this.growthDirection); + + if (this.canGrowInto(world.getBlockState(blockposition1))) { +- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random)); // CraftBukkit ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random, world)); // CraftBukkit // Paper - Fix Spigot growth modifiers + } + } + + } + ++ // Paper start - Fix Spigot growth modifiers ++ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) { ++ return this.getGrowIntoState(state, random); ++ } ++ // Paper end - Fix Spigot growth modifiers ++ + protected BlockState getGrowIntoState(BlockState state, RandomSource random) { + return (BlockState) state.cycle(GrowingPlantHeadBlock.AGE); + } +diff --git a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java +index 10e2b80b0b6010982258548b5084b9591177b558..6b18db68c8b95480992199126c6063ea728d2314 100644 +--- a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java +@@ -123,7 +123,7 @@ public class MangrovePropaguleBlock extends SaplingBlock implements SimpleWaterl + @Override + protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { + if (!isHanging(state)) { +- if (random.nextInt(7) == 0) { ++ if (random.nextFloat() < (world.spigotConfig.saplingModifier / (100.0F * 7))) { // Paper - Fix Spigot growth modifiers + this.advanceTree(world, pos, state, random); + } + } else { +diff --git a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java +index 972d8833127090c01d620cab10b3eca3d3601710..ea6135edc76c06b7cd55930b620dfb05f939e4f6 100644 +--- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java +@@ -132,7 +132,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl + @Override + public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { + float f = CropBlock.getGrowthSpeed(this, world, pos); +- boolean bl = random.nextInt((int)(25.0F / f) + 1) == 0; ++ boolean bl = random.nextFloat() < (world.spigotConfig.pitcherPlantModifier / (100.0F * (Math.floor(25.0F / f) + 1))); // Paper - Fix Spigot growth modifiers + if (bl) { + this.grow(world, state, pos, 1); + } +diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java +index 491dd55b2870093184a606efabd251c68cc24719..e76f96a5c48d1eda2f9bbb3e11dd79f23f9ab75c 100644 +--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java ++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java +@@ -96,6 +96,7 @@ public class SpigotWorldConfig + public int beetrootModifier; + public int carrotModifier; + public int potatoModifier; ++ public int torchFlowerModifier; // Paper + public int wheatModifier; + public int wartModifier; + public int vineModifier; +@@ -106,6 +107,8 @@ public class SpigotWorldConfig + public int twistingVinesModifier; + public int weepingVinesModifier; + public int caveVinesModifier; ++ public int glowBerryModifier; // Paper ++ public int pitcherPlantModifier; // Paper + private int getAndValidateGrowth(String crop) + { + int modifier = this.getInt( "growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100 ); +@@ -129,6 +132,7 @@ public class SpigotWorldConfig + this.beetrootModifier = this.getAndValidateGrowth( "Beetroot" ); + this.carrotModifier = this.getAndValidateGrowth( "Carrot" ); + this.potatoModifier = this.getAndValidateGrowth( "Potato" ); ++ this.torchFlowerModifier = this.getAndValidateGrowth("TorchFlower"); // Paper + this.wheatModifier = this.getAndValidateGrowth( "Wheat" ); + this.wartModifier = this.getAndValidateGrowth( "NetherWart" ); + this.vineModifier = this.getAndValidateGrowth( "Vine" ); +@@ -139,6 +143,8 @@ public class SpigotWorldConfig + this.twistingVinesModifier = this.getAndValidateGrowth( "TwistingVines" ); + this.weepingVinesModifier = this.getAndValidateGrowth( "WeepingVines" ); + this.caveVinesModifier = this.getAndValidateGrowth( "CaveVines" ); ++ this.glowBerryModifier = this.getAndValidateGrowth("GlowBerry"); // Paper ++ this.pitcherPlantModifier = this.getAndValidateGrowth("PitcherPlant"); // Paper + } + + public double itemMerge; diff --git a/patches/server/0624-Remove-client-side-code-using-deprecated-for-removal.patch b/patches/server/0624-Remove-client-side-code-using-deprecated-for-removal.patch deleted file mode 100644 index 1a9d2657f1..0000000000 --- a/patches/server/0624-Remove-client-side-code-using-deprecated-for-removal.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Fri, 26 Nov 2021 15:09:58 -0800 -Subject: [PATCH] Remove client-side code using deprecated for removal - AccessController - -Fixes warnings on build - -diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java -index bf2833c92eca6491699b4a89410e4e46b5bbe4d1..57223285860f61119b6cf348aa78e59384a04e22 100644 ---- a/src/main/java/net/minecraft/Util.java -+++ b/src/main/java/net/minecraft/Util.java -@@ -1082,16 +1082,7 @@ public class Util { - } - - public void openUri(URI uri) { -- try { -- Process process = AccessController.doPrivileged( -- (PrivilegedExceptionAction)(() -> Runtime.getRuntime().exec(this.getOpenUriArguments(uri))) -- ); -- process.getInputStream().close(); -- process.getErrorStream().close(); -- process.getOutputStream().close(); -- } catch (IOException | PrivilegedActionException var3) { -- Util.LOGGER.error("Couldn't open location '{}'", uri, var3); -- } -+ throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code - } - - public void openFile(File file) { diff --git a/patches/server/0625-Fix-Spigot-growth-modifiers.patch b/patches/server/0625-Fix-Spigot-growth-modifiers.patch deleted file mode 100644 index 6a24adf1c8..0000000000 --- a/patches/server/0625-Fix-Spigot-growth-modifiers.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Fri, 3 Dec 2021 17:09:24 -0800 -Subject: [PATCH] Fix Spigot growth modifiers - -Fixes kelp modifier changing growth for other crops -Also add growth modifiers for glow berries, mangrove propagules, -torchflower crops and pitcher plant crops -Also fix above-mentioned modifiers from having the reverse effect - -Co-authored-by: Jake Potrebic -Co-authored-by: Noah van der Aa -Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> - -diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -index 437be546cf03b6af0856adabfeaf67bc33ff75d6..c4473c2a778116d48bc3e4796afd901f455070e6 100644 ---- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -@@ -50,9 +50,18 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements CaveVines { - return to.setValue(BERRIES, from.getValue(BERRIES)); - } - -+ // Paper start - Fix Spigot growth modifiers -+ @Override -+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) { -+ final boolean value = random.nextFloat() < (level != null ? (0.11F * (level.spigotConfig.glowBerryModifier / 100.0F)) : 0.11F); -+ return (BlockState) super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, value); -+ } -+ // Paper end - Fix Spigot growth modifiers -+ - @Override - protected BlockState getGrowIntoState(BlockState state, RandomSource random) { -- return super.getGrowIntoState(state, random).setValue(BERRIES, Boolean.valueOf(random.nextFloat() < 0.11F)); -+ // Paper start - Fix Spigot growth modifiers -+ return this.getGrowIntoState(state, random, null); - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java -index 79ebc37a779bf6cba66a34a7604f819e95fd86a2..1ada5ed825501666addacf527a513ab7bd4a3a58 100644 ---- a/src/main/java/net/minecraft/world/level/block/CropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java -@@ -91,6 +91,10 @@ public class CropBlock extends BushBlock implements BonemealableBlock { - modifier = world.spigotConfig.carrotModifier; - } else if (this == Blocks.POTATOES) { - modifier = world.spigotConfig.potatoModifier; -+ // Paper start - Fix Spigot growth modifiers -+ } else if (this == Blocks.TORCHFLOWER_CROP) { -+ modifier = world.spigotConfig.torchFlowerModifier; -+ // Paper end - Fix Spigot growth modifiers - } else { - modifier = world.spigotConfig.wheatModifier; - } -diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -index c527f2d8f594d711d047a2a149efe37caaeb0308..9b424d7661fedf8ee1eb9f3167c62e563f04d4d1 100644 ---- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -@@ -60,12 +60,18 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements - BlockPos blockposition1 = pos.relative(this.growthDirection); - - if (this.canGrowInto(world.getBlockState(blockposition1))) { -- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random)); // CraftBukkit -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random, world)); // CraftBukkit // Paper - Fix Spigot growth modifiers - } - } - - } - -+ // Paper start - Fix Spigot growth modifiers -+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) { -+ return this.getGrowIntoState(state, random); -+ } -+ // Paper end - Fix Spigot growth modifiers -+ - protected BlockState getGrowIntoState(BlockState state, RandomSource random) { - return (BlockState) state.cycle(GrowingPlantHeadBlock.AGE); - } -diff --git a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java -index 10e2b80b0b6010982258548b5084b9591177b558..6b18db68c8b95480992199126c6063ea728d2314 100644 ---- a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java -@@ -123,7 +123,7 @@ public class MangrovePropaguleBlock extends SaplingBlock implements SimpleWaterl - @Override - protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { - if (!isHanging(state)) { -- if (random.nextInt(7) == 0) { -+ if (random.nextFloat() < (world.spigotConfig.saplingModifier / (100.0F * 7))) { // Paper - Fix Spigot growth modifiers - this.advanceTree(world, pos, state, random); - } - } else { -diff --git a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -index 972d8833127090c01d620cab10b3eca3d3601710..ea6135edc76c06b7cd55930b620dfb05f939e4f6 100644 ---- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -@@ -132,7 +132,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl - @Override - public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { - float f = CropBlock.getGrowthSpeed(this, world, pos); -- boolean bl = random.nextInt((int)(25.0F / f) + 1) == 0; -+ boolean bl = random.nextFloat() < (world.spigotConfig.pitcherPlantModifier / (100.0F * (Math.floor(25.0F / f) + 1))); // Paper - Fix Spigot growth modifiers - if (bl) { - this.grow(world, state, pos, 1); - } -diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java -index 491dd55b2870093184a606efabd251c68cc24719..e76f96a5c48d1eda2f9bbb3e11dd79f23f9ab75c 100644 ---- a/src/main/java/org/spigotmc/SpigotWorldConfig.java -+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java -@@ -96,6 +96,7 @@ public class SpigotWorldConfig - public int beetrootModifier; - public int carrotModifier; - public int potatoModifier; -+ public int torchFlowerModifier; // Paper - public int wheatModifier; - public int wartModifier; - public int vineModifier; -@@ -106,6 +107,8 @@ public class SpigotWorldConfig - public int twistingVinesModifier; - public int weepingVinesModifier; - public int caveVinesModifier; -+ public int glowBerryModifier; // Paper -+ public int pitcherPlantModifier; // Paper - private int getAndValidateGrowth(String crop) - { - int modifier = this.getInt( "growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100 ); -@@ -129,6 +132,7 @@ public class SpigotWorldConfig - this.beetrootModifier = this.getAndValidateGrowth( "Beetroot" ); - this.carrotModifier = this.getAndValidateGrowth( "Carrot" ); - this.potatoModifier = this.getAndValidateGrowth( "Potato" ); -+ this.torchFlowerModifier = this.getAndValidateGrowth("TorchFlower"); // Paper - this.wheatModifier = this.getAndValidateGrowth( "Wheat" ); - this.wartModifier = this.getAndValidateGrowth( "NetherWart" ); - this.vineModifier = this.getAndValidateGrowth( "Vine" ); -@@ -139,6 +143,8 @@ public class SpigotWorldConfig - this.twistingVinesModifier = this.getAndValidateGrowth( "TwistingVines" ); - this.weepingVinesModifier = this.getAndValidateGrowth( "WeepingVines" ); - this.caveVinesModifier = this.getAndValidateGrowth( "CaveVines" ); -+ this.glowBerryModifier = this.getAndValidateGrowth("GlowBerry"); // Paper -+ this.pitcherPlantModifier = this.getAndValidateGrowth("PitcherPlant"); // Paper - } - - public double itemMerge; diff --git a/patches/server/0625-Prevent-ContainerOpenersCounter-openCount-from-going.patch b/patches/server/0625-Prevent-ContainerOpenersCounter-openCount-from-going.patch new file mode 100644 index 0000000000..b017de75d1 --- /dev/null +++ b/patches/server/0625-Prevent-ContainerOpenersCounter-openCount-from-going.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Tue, 30 Nov 2021 05:30:35 +0000 +Subject: [PATCH] Prevent ContainerOpenersCounter openCount from going negative + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java +index 43e4e893f0e7eed1959e6ccfa43c39ff00f083b3..86dce6796f92a5b0ae2b1bd837267c4e3f6754d0 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java +@@ -69,6 +69,7 @@ public abstract class ContainerOpenersCounter { + + public void decrementOpeners(Player player, Level world, BlockPos pos, BlockState state) { + int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added ++ if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative + int i = this.openCount--; + + // CraftBukkit start - Call redstone event diff --git a/patches/server/0626-Add-PlayerItemFrameChangeEvent.patch b/patches/server/0626-Add-PlayerItemFrameChangeEvent.patch new file mode 100644 index 0000000000..b7e908ab6e --- /dev/null +++ b/patches/server/0626-Add-PlayerItemFrameChangeEvent.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SamB440 +Date: Mon, 15 Nov 2021 18:10:10 +0000 +Subject: [PATCH] Add PlayerItemFrameChangeEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java +index c0deabf9d86d086fbd8cbaac5a02badf5c01c870..30af4cbb17148c247a46c0346419d6c838dbc9d2 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java +@@ -1,6 +1,7 @@ + package net.minecraft.world.entity.decoration; + + import javax.annotation.Nullable; ++import io.papermc.paper.event.player.PlayerItemFrameChangeEvent; // Paper - Add PlayerItemFrameChangeEvent + import net.minecraft.core.BlockPos; + import net.minecraft.core.Direction; + import net.minecraft.core.component.DataComponents; +@@ -166,6 +167,13 @@ public class ItemFrame extends HangingEntity { + return true; + } + // CraftBukkit end ++ // Paper start - Add PlayerItemFrameChangeEvent ++ if (source.getEntity() instanceof Player player) { ++ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE); ++ if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change ++ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false); ++ } ++ // Paper end - Add PlayerItemFrameChangeEvent + this.dropItem(world, source.getEntity(), false); + this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity()); + this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F); +@@ -403,7 +411,13 @@ public class ItemFrame extends HangingEntity { + if (worldmap != null && worldmap.isTrackedCountOverLimit(256)) { + return InteractionResult.FAIL; + } else { +- this.setItem(itemstack); ++ // Paper start - Add PlayerItemFrameChangeEvent ++ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemstack.asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); ++ if (!event.callEvent()) { ++ return InteractionResult.FAIL; ++ } ++ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack())); ++ // Paper end - Add PlayerItemFrameChangeEvent + this.gameEvent(GameEvent.BLOCK_CHANGE, player); + itemstack.consume(1, player); + return InteractionResult.SUCCESS; +@@ -412,6 +426,13 @@ public class ItemFrame extends HangingEntity { + return InteractionResult.PASS; + } + } else { ++ // Paper start - Add PlayerItemFrameChangeEvent ++ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.ROTATE); ++ if (!event.callEvent()) { ++ return InteractionResult.FAIL; ++ } ++ setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false, false); ++ // Paper end - Add PlayerItemFrameChangeEvent + this.playSound(this.getRotateItemSound(), 1.0F, 1.0F); + this.setRotation(this.getRotation() + 1); + this.gameEvent(GameEvent.BLOCK_CHANGE, player); diff --git a/patches/server/0626-Prevent-ContainerOpenersCounter-openCount-from-going.patch b/patches/server/0626-Prevent-ContainerOpenersCounter-openCount-from-going.patch deleted file mode 100644 index b017de75d1..0000000000 --- a/patches/server/0626-Prevent-ContainerOpenersCounter-openCount-from-going.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Tue, 30 Nov 2021 05:30:35 +0000 -Subject: [PATCH] Prevent ContainerOpenersCounter openCount from going negative - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java -index 43e4e893f0e7eed1959e6ccfa43c39ff00f083b3..86dce6796f92a5b0ae2b1bd837267c4e3f6754d0 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java -@@ -69,6 +69,7 @@ public abstract class ContainerOpenersCounter { - - public void decrementOpeners(Player player, Level world, BlockPos pos, BlockState state) { - int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added -+ if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative - int i = this.openCount--; - - // CraftBukkit start - Call redstone event diff --git a/patches/server/0627-Add-PlayerItemFrameChangeEvent.patch b/patches/server/0627-Add-PlayerItemFrameChangeEvent.patch deleted file mode 100644 index b7e908ab6e..0000000000 --- a/patches/server/0627-Add-PlayerItemFrameChangeEvent.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SamB440 -Date: Mon, 15 Nov 2021 18:10:10 +0000 -Subject: [PATCH] Add PlayerItemFrameChangeEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -index c0deabf9d86d086fbd8cbaac5a02badf5c01c870..30af4cbb17148c247a46c0346419d6c838dbc9d2 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -@@ -1,6 +1,7 @@ - package net.minecraft.world.entity.decoration; - - import javax.annotation.Nullable; -+import io.papermc.paper.event.player.PlayerItemFrameChangeEvent; // Paper - Add PlayerItemFrameChangeEvent - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; - import net.minecraft.core.component.DataComponents; -@@ -166,6 +167,13 @@ public class ItemFrame extends HangingEntity { - return true; - } - // CraftBukkit end -+ // Paper start - Add PlayerItemFrameChangeEvent -+ if (source.getEntity() instanceof Player player) { -+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE); -+ if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change -+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false); -+ } -+ // Paper end - Add PlayerItemFrameChangeEvent - this.dropItem(world, source.getEntity(), false); - this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity()); - this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F); -@@ -403,7 +411,13 @@ public class ItemFrame extends HangingEntity { - if (worldmap != null && worldmap.isTrackedCountOverLimit(256)) { - return InteractionResult.FAIL; - } else { -- this.setItem(itemstack); -+ // Paper start - Add PlayerItemFrameChangeEvent -+ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemstack.asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); -+ if (!event.callEvent()) { -+ return InteractionResult.FAIL; -+ } -+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack())); -+ // Paper end - Add PlayerItemFrameChangeEvent - this.gameEvent(GameEvent.BLOCK_CHANGE, player); - itemstack.consume(1, player); - return InteractionResult.SUCCESS; -@@ -412,6 +426,13 @@ public class ItemFrame extends HangingEntity { - return InteractionResult.PASS; - } - } else { -+ // Paper start - Add PlayerItemFrameChangeEvent -+ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.ROTATE); -+ if (!event.callEvent()) { -+ return InteractionResult.FAIL; -+ } -+ setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false, false); -+ // Paper end - Add PlayerItemFrameChangeEvent - this.playSound(this.getRotateItemSound(), 1.0F, 1.0F); - this.setRotation(this.getRotation() + 1); - this.gameEvent(GameEvent.BLOCK_CHANGE, player); diff --git a/patches/server/0627-Optimize-HashMapPalette.patch b/patches/server/0627-Optimize-HashMapPalette.patch new file mode 100644 index 0000000000..a490eb0c20 --- /dev/null +++ b/patches/server/0627-Optimize-HashMapPalette.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: stonar96 +Date: Sun, 17 Jan 2021 01:11:36 +0100 +Subject: [PATCH] Optimize HashMapPalette + +HashMapPalette uses an instance of CrudeIncrementalIntIdentityHashBiMap +internally. A Palette has a preset maximum size = 1 << bits. +CrudeIncrementalIntIdentityHashBiMap has an initial size but is +automatically resized. The CrudeIncrementalIntIdentityHashBiMap is created +with the maximum size in the constructor of HashMapPalette, with the aim +that it doesn't need to be resized anymore. However, there are two things +that I think Mojang hasn't considered here: +1) The CrudeIncrementalIntIdentityHashBiMap is resized, when its initial +size is reached and not the next time, when a further object is added. +2) HashMapPalette adds objects (unnecessarily) before checking if the +initial size of CrudeIncrementalIntIdentityHashBiMap is reached. +This means to actually avoid resize operations in +CrudeIncrementalIntIdentityHashBiMap, one has to add 2 to the initial size +or add 1 and check the size before adding objects. This commit implements +the second approach. Note that this isn't only an optimization but also +makes async reads of Palettes fail-safe. An async read while the +CrudeIncrementalIntIdentityHashBiMap is resized is fatal and can even lead +to corrupted data. This is also something that Anti-Xray is currently +relying on. + +diff --git a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java +index ac673cb38755852eef37e915f157f6a702117306..98dbeaf8bde15940e5b5d5d1f13fd4bb32f0a10d 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java ++++ b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java +@@ -20,7 +20,7 @@ public class HashMapPalette implements Palette { + } + + public HashMapPalette(IdMap idList, int indexBits, PaletteResize listener) { +- this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create(1 << indexBits)); ++ this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create((1 << indexBits) + 1)); // Paper - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap + } + + private HashMapPalette(IdMap idList, int indexBits, PaletteResize listener, CrudeIncrementalIntIdentityHashBiMap map) { +@@ -38,10 +38,16 @@ public class HashMapPalette implements Palette { + public int idFor(T object) { + int i = this.values.getId(object); + if (i == -1) { +- i = this.values.add(object); +- if (i >= 1 << this.bits) { ++ // Paper start - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize ++ // We use size() instead of the result from add(K) ++ // This avoids adding another object unnecessarily ++ // Without this change, + 2 would be required in the constructor ++ if (this.values.size() >= 1 << this.bits) { + i = this.resizeHandler.onResize(this.bits + 1, object); ++ } else { ++ i = this.values.add(object); + } ++ // Paper end - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize + } + + return i; diff --git a/patches/server/0628-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch b/patches/server/0628-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch new file mode 100644 index 0000000000..50968cdc50 --- /dev/null +++ b/patches/server/0628-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Thu, 9 Dec 2021 00:08:11 -0800 +Subject: [PATCH] Fix ChunkSnapshot#isSectionEmpty(int) and optimize + PalettedContainer copying by not using codecs + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +index b2d85abb6c9c725955d972cd6895440849213fdf..887a17a0833064eb5701222e5fb6f5ccf9511588 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +@@ -338,14 +338,17 @@ public class CraftChunk implements Chunk { + PalettedContainerRO>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null; + + Registry iregistry = this.worldServer.registryAccess().lookupOrThrow(Registries.BIOME); +- Codec>> biomeCodec = PalettedContainer.codecRO(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS)); + + for (int i = 0; i < cs.length; i++) { +- CompoundTag data = new CompoundTag(); + +- data.put("block_states", SerializableChunkData.BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, cs[i].getStates()).getOrThrow()); +- sectionBlockIDs[i] = SerializableChunkData.BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, data.getCompound("block_states")).getOrThrow(SerializableChunkData.ChunkReadException::new); +- sectionEmpty[i] = cs[i].hasOnlyAir(); ++ // Paper start - Fix ChunkSnapshot#isSectionEmpty(int); and remove codec usage ++ sectionEmpty[i] = cs[i].hasOnlyAir(); // fix sectionEmpty array not being filled ++ if (!sectionEmpty[i]) { ++ sectionBlockIDs[i] = cs[i].getStates().copy(); // use copy instead of round tripping with codecs ++ } else { ++ sectionBlockIDs[i] = CraftChunk.emptyBlockIDs; // use cached instance for empty block sections ++ } ++ // Paper end - Fix ChunkSnapshot#isSectionEmpty(int) + + LevelLightEngine lightengine = this.worldServer.getLightEngine(); + DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index +@@ -364,8 +367,7 @@ public class CraftChunk implements Chunk { + } + + if (biome != null) { +- data.put("biomes", biomeCodec.encodeStart(NbtOps.INSTANCE, cs[i].getBiomes()).getOrThrow()); +- biome[i] = biomeCodec.parse(NbtOps.INSTANCE, data.getCompound("biomes")).getOrThrow(SerializableChunkData.ChunkReadException::new); ++ biome[i] = ((PalettedContainer>) cs[i].getBiomes()).copy(); // Paper - Perf: use copy instead of round tripping with codecs + } + } + diff --git a/patches/server/0628-Optimize-HashMapPalette.patch b/patches/server/0628-Optimize-HashMapPalette.patch deleted file mode 100644 index a490eb0c20..0000000000 --- a/patches/server/0628-Optimize-HashMapPalette.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: stonar96 -Date: Sun, 17 Jan 2021 01:11:36 +0100 -Subject: [PATCH] Optimize HashMapPalette - -HashMapPalette uses an instance of CrudeIncrementalIntIdentityHashBiMap -internally. A Palette has a preset maximum size = 1 << bits. -CrudeIncrementalIntIdentityHashBiMap has an initial size but is -automatically resized. The CrudeIncrementalIntIdentityHashBiMap is created -with the maximum size in the constructor of HashMapPalette, with the aim -that it doesn't need to be resized anymore. However, there are two things -that I think Mojang hasn't considered here: -1) The CrudeIncrementalIntIdentityHashBiMap is resized, when its initial -size is reached and not the next time, when a further object is added. -2) HashMapPalette adds objects (unnecessarily) before checking if the -initial size of CrudeIncrementalIntIdentityHashBiMap is reached. -This means to actually avoid resize operations in -CrudeIncrementalIntIdentityHashBiMap, one has to add 2 to the initial size -or add 1 and check the size before adding objects. This commit implements -the second approach. Note that this isn't only an optimization but also -makes async reads of Palettes fail-safe. An async read while the -CrudeIncrementalIntIdentityHashBiMap is resized is fatal and can even lead -to corrupted data. This is also something that Anti-Xray is currently -relying on. - -diff --git a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java -index ac673cb38755852eef37e915f157f6a702117306..98dbeaf8bde15940e5b5d5d1f13fd4bb32f0a10d 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java -+++ b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java -@@ -20,7 +20,7 @@ public class HashMapPalette implements Palette { - } - - public HashMapPalette(IdMap idList, int indexBits, PaletteResize listener) { -- this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create(1 << indexBits)); -+ this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create((1 << indexBits) + 1)); // Paper - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap - } - - private HashMapPalette(IdMap idList, int indexBits, PaletteResize listener, CrudeIncrementalIntIdentityHashBiMap map) { -@@ -38,10 +38,16 @@ public class HashMapPalette implements Palette { - public int idFor(T object) { - int i = this.values.getId(object); - if (i == -1) { -- i = this.values.add(object); -- if (i >= 1 << this.bits) { -+ // Paper start - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize -+ // We use size() instead of the result from add(K) -+ // This avoids adding another object unnecessarily -+ // Without this change, + 2 would be required in the constructor -+ if (this.values.size() >= 1 << this.bits) { - i = this.resizeHandler.onResize(this.bits + 1, object); -+ } else { -+ i = this.values.add(object); - } -+ // Paper end - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize - } - - return i; diff --git a/patches/server/0629-Add-more-Campfire-API.patch b/patches/server/0629-Add-more-Campfire-API.patch new file mode 100644 index 0000000000..c490c151c3 --- /dev/null +++ b/patches/server/0629-Add-more-Campfire-API.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: LemonCaramel +Date: Fri, 16 Jul 2021 00:39:03 +0900 +Subject: [PATCH] Add more Campfire API + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java +index 7fa1aea7942a1bc4d9779a9f8ab020ccd5566923..94072a9b65f69dfc3337907f8573081989467662 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java +@@ -46,12 +46,14 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { + private final NonNullList items; + public final int[] cookingProgress; + public final int[] cookingTime; ++ public final boolean[] stopCooking; // Paper - Add more Campfire API + + public CampfireBlockEntity(BlockPos pos, BlockState state) { + super(BlockEntityType.CAMPFIRE, pos, state); + this.items = NonNullList.withSize(4, ItemStack.EMPTY); + this.cookingProgress = new int[4]; + this.cookingTime = new int[4]; ++ this.stopCooking = new boolean[4]; // Paper - Add more Campfire API + } + + public static void cookTick(ServerLevel world, BlockPos pos, BlockState state, CampfireBlockEntity blockEntity, RecipeManager.CachedCheck recipeMatchGetter) { +@@ -62,7 +64,9 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { + + if (!itemstack.isEmpty()) { + flag = true; ++ if (!blockEntity.stopCooking[i]) { // Paper - Add more Campfire API + int j = blockEntity.cookingProgress[i]++; ++ } // Paper - Add more Campfire API + + if (blockEntity.cookingProgress[i] >= blockEntity.cookingTime[i]) { + SingleRecipeInput singlerecipeinput = new SingleRecipeInput(itemstack); +@@ -175,6 +179,16 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { + System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length)); + } + ++ // Paper start - Add more Campfire API ++ if (nbt.contains("Paper.StopCooking", org.bukkit.craftbukkit.util.CraftMagicNumbers.NBT.TAG_BYTE_ARRAY)) { ++ byte[] abyte = nbt.getByteArray("Paper.StopCooking"); ++ boolean[] cookingState = new boolean[4]; ++ for (int index = 0; index < abyte.length; index++) { ++ cookingState[index] = abyte[index] == 1; ++ } ++ System.arraycopy(cookingState, 0, this.stopCooking, 0, Math.min(this.stopCooking.length, abyte.length)); ++ } ++ // Paper end - Add more Campfire API + } + + @Override +@@ -183,6 +197,13 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { + ContainerHelper.saveAllItems(nbt, this.items, true, registries); + nbt.putIntArray("CookingTimes", this.cookingProgress); + nbt.putIntArray("CookingTotalTimes", this.cookingTime); ++ // Paper start - Add more Campfire API ++ byte[] cookingState = new byte[4]; ++ for (int index = 0; index < cookingState.length; index++) { ++ cookingState[index] = (byte) (this.stopCooking[index] ? 1 : 0); ++ } ++ nbt.putByteArray("Paper.StopCooking", cookingState); ++ // Paper end - Add more Campfire API + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java +index 4850cbf2c326f1155e04a204abed2d200c02342d..a776bba2ec51c6aecce98a3abceb2c235522d99d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java +@@ -62,4 +62,40 @@ public class CraftCampfire extends CraftBlockEntityState im + public CraftCampfire copy(Location location) { + return new CraftCampfire(this, location); + } ++ ++ // Paper start ++ @Override ++ public void stopCooking() { ++ for (int i = 0; i < getSnapshot().stopCooking.length; ++i) ++ this.stopCooking(i); ++ } ++ ++ @Override ++ public void startCooking() { ++ for (int i = 0; i < getSnapshot().stopCooking.length; ++i) ++ this.startCooking(i); ++ } ++ ++ @Override ++ public boolean stopCooking(int index) { ++ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); ++ boolean previous = this.isCookingDisabled(index); ++ getSnapshot().stopCooking[index] = true; ++ return previous; ++ } ++ ++ @Override ++ public boolean startCooking(int index) { ++ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); ++ boolean previous = this.isCookingDisabled(index); ++ getSnapshot().stopCooking[index] = false; ++ return previous; ++ } ++ ++ @Override ++ public boolean isCookingDisabled(int index) { ++ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); ++ return getSnapshot().stopCooking[index]; ++ } ++ // Paper end + } diff --git a/patches/server/0629-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch b/patches/server/0629-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch deleted file mode 100644 index 50968cdc50..0000000000 --- a/patches/server/0629-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Thu, 9 Dec 2021 00:08:11 -0800 -Subject: [PATCH] Fix ChunkSnapshot#isSectionEmpty(int) and optimize - PalettedContainer copying by not using codecs - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -index b2d85abb6c9c725955d972cd6895440849213fdf..887a17a0833064eb5701222e5fb6f5ccf9511588 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -@@ -338,14 +338,17 @@ public class CraftChunk implements Chunk { - PalettedContainerRO>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null; - - Registry iregistry = this.worldServer.registryAccess().lookupOrThrow(Registries.BIOME); -- Codec>> biomeCodec = PalettedContainer.codecRO(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS)); - - for (int i = 0; i < cs.length; i++) { -- CompoundTag data = new CompoundTag(); - -- data.put("block_states", SerializableChunkData.BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, cs[i].getStates()).getOrThrow()); -- sectionBlockIDs[i] = SerializableChunkData.BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, data.getCompound("block_states")).getOrThrow(SerializableChunkData.ChunkReadException::new); -- sectionEmpty[i] = cs[i].hasOnlyAir(); -+ // Paper start - Fix ChunkSnapshot#isSectionEmpty(int); and remove codec usage -+ sectionEmpty[i] = cs[i].hasOnlyAir(); // fix sectionEmpty array not being filled -+ if (!sectionEmpty[i]) { -+ sectionBlockIDs[i] = cs[i].getStates().copy(); // use copy instead of round tripping with codecs -+ } else { -+ sectionBlockIDs[i] = CraftChunk.emptyBlockIDs; // use cached instance for empty block sections -+ } -+ // Paper end - Fix ChunkSnapshot#isSectionEmpty(int) - - LevelLightEngine lightengine = this.worldServer.getLightEngine(); - DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index -@@ -364,8 +367,7 @@ public class CraftChunk implements Chunk { - } - - if (biome != null) { -- data.put("biomes", biomeCodec.encodeStart(NbtOps.INSTANCE, cs[i].getBiomes()).getOrThrow()); -- biome[i] = biomeCodec.parse(NbtOps.INSTANCE, data.getCompound("biomes")).getOrThrow(SerializableChunkData.ChunkReadException::new); -+ biome[i] = ((PalettedContainer>) cs[i].getBiomes()).copy(); // Paper - Perf: use copy instead of round tripping with codecs - } - } - diff --git a/patches/server/0630-Add-more-Campfire-API.patch b/patches/server/0630-Add-more-Campfire-API.patch deleted file mode 100644 index c490c151c3..0000000000 --- a/patches/server/0630-Add-more-Campfire-API.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LemonCaramel -Date: Fri, 16 Jul 2021 00:39:03 +0900 -Subject: [PATCH] Add more Campfire API - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java -index 7fa1aea7942a1bc4d9779a9f8ab020ccd5566923..94072a9b65f69dfc3337907f8573081989467662 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java -@@ -46,12 +46,14 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { - private final NonNullList items; - public final int[] cookingProgress; - public final int[] cookingTime; -+ public final boolean[] stopCooking; // Paper - Add more Campfire API - - public CampfireBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.CAMPFIRE, pos, state); - this.items = NonNullList.withSize(4, ItemStack.EMPTY); - this.cookingProgress = new int[4]; - this.cookingTime = new int[4]; -+ this.stopCooking = new boolean[4]; // Paper - Add more Campfire API - } - - public static void cookTick(ServerLevel world, BlockPos pos, BlockState state, CampfireBlockEntity blockEntity, RecipeManager.CachedCheck recipeMatchGetter) { -@@ -62,7 +64,9 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { - - if (!itemstack.isEmpty()) { - flag = true; -+ if (!blockEntity.stopCooking[i]) { // Paper - Add more Campfire API - int j = blockEntity.cookingProgress[i]++; -+ } // Paper - Add more Campfire API - - if (blockEntity.cookingProgress[i] >= blockEntity.cookingTime[i]) { - SingleRecipeInput singlerecipeinput = new SingleRecipeInput(itemstack); -@@ -175,6 +179,16 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { - System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length)); - } - -+ // Paper start - Add more Campfire API -+ if (nbt.contains("Paper.StopCooking", org.bukkit.craftbukkit.util.CraftMagicNumbers.NBT.TAG_BYTE_ARRAY)) { -+ byte[] abyte = nbt.getByteArray("Paper.StopCooking"); -+ boolean[] cookingState = new boolean[4]; -+ for (int index = 0; index < abyte.length; index++) { -+ cookingState[index] = abyte[index] == 1; -+ } -+ System.arraycopy(cookingState, 0, this.stopCooking, 0, Math.min(this.stopCooking.length, abyte.length)); -+ } -+ // Paper end - Add more Campfire API - } - - @Override -@@ -183,6 +197,13 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { - ContainerHelper.saveAllItems(nbt, this.items, true, registries); - nbt.putIntArray("CookingTimes", this.cookingProgress); - nbt.putIntArray("CookingTotalTimes", this.cookingTime); -+ // Paper start - Add more Campfire API -+ byte[] cookingState = new byte[4]; -+ for (int index = 0; index < cookingState.length; index++) { -+ cookingState[index] = (byte) (this.stopCooking[index] ? 1 : 0); -+ } -+ nbt.putByteArray("Paper.StopCooking", cookingState); -+ // Paper end - Add more Campfire API - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java -index 4850cbf2c326f1155e04a204abed2d200c02342d..a776bba2ec51c6aecce98a3abceb2c235522d99d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java -@@ -62,4 +62,40 @@ public class CraftCampfire extends CraftBlockEntityState im - public CraftCampfire copy(Location location) { - return new CraftCampfire(this, location); - } -+ -+ // Paper start -+ @Override -+ public void stopCooking() { -+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i) -+ this.stopCooking(i); -+ } -+ -+ @Override -+ public void startCooking() { -+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i) -+ this.startCooking(i); -+ } -+ -+ @Override -+ public boolean stopCooking(int index) { -+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); -+ boolean previous = this.isCookingDisabled(index); -+ getSnapshot().stopCooking[index] = true; -+ return previous; -+ } -+ -+ @Override -+ public boolean startCooking(int index) { -+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); -+ boolean previous = this.isCookingDisabled(index); -+ getSnapshot().stopCooking[index] = false; -+ return previous; -+ } -+ -+ @Override -+ public boolean isCookingDisabled(int index) { -+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); -+ return getSnapshot().stopCooking[index]; -+ } -+ // Paper end - } diff --git a/patches/server/0630-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch b/patches/server/0630-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch new file mode 100644 index 0000000000..80c053acc6 --- /dev/null +++ b/patches/server/0630-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch @@ -0,0 +1,94 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 19 Dec 2021 09:13:41 -0800 +Subject: [PATCH] Only write chunk data to disk if it serializes without + throwing + +This ensures at least a valid version of the chunk exists +on disk, even if outdated + +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +index 12b7d50f49a2184aaf220a4a50a137b217c57124..f1237f6fd6414900ffbad0caee31aa83310eeef4 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +@@ -442,6 +442,7 @@ public class RegionFile implements AutoCloseable { + + } + ++ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails + private class ChunkBuffer extends ByteArrayOutputStream { + + private final ChunkPos pos; +@@ -455,6 +456,23 @@ public class RegionFile implements AutoCloseable { + super.write(RegionFile.this.version.getId()); + this.pos = chunkcoordintpair; + } ++ // Paper start - don't write garbage data to disk if writing serialization fails ++ @Override ++ public void write(final int b) { ++ if (this.count > MAX_CHUNK_SIZE) { ++ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + this.count); ++ } ++ super.write(b); ++ } ++ ++ @Override ++ public void write(final byte[] b, final int off, final int len) { ++ if (this.count + len > MAX_CHUNK_SIZE) { ++ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + (this.count + len)); ++ } ++ super.write(b, off, len); ++ } ++ // Paper end - don't write garbage data to disk if writing serialization fails + + public void close() throws IOException { + ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +index 491035aaefff4ee96435ec5d3f9417e28eae0796..4c1212c6ef48594e766fa9e35a6e15916602d587 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +@@ -147,10 +147,17 @@ public final class RegionFileStorage implements AutoCloseable { + + try { + NbtIo.write(nbt, (DataOutput) dataoutputstream); ++ // Paper start - don't write garbage data to disk if writing serialization fails ++ dataoutputstream.close(); // Only write if successful ++ } catch (final RegionFileSizeException e) { ++ attempts = 5; // Don't retry ++ regionfile.clear(pos); ++ throw e; ++ // Paper end - don't write garbage data to disk if writing serialization fails + } catch (Throwable throwable) { + if (dataoutputstream != null) { + try { +- dataoutputstream.close(); ++ //dataoutputstream.close(); // Paper - don't write garbage data to disk if writing serialization fails + } catch (Throwable throwable1) { + throwable.addSuppressed(throwable1); + } +@@ -158,10 +165,7 @@ public final class RegionFileStorage implements AutoCloseable { + + throw throwable; + } +- +- if (dataoutputstream != null) { +- dataoutputstream.close(); +- } ++ // Paper - don't write garbage data to disk if writing serialization fails; move into try block to only write if successfully serialized + } + // Paper start - Chunk save reattempt + return; +@@ -208,4 +212,13 @@ public final class RegionFileStorage implements AutoCloseable { + public RegionStorageInfo info() { + return this.info; + } ++ ++ // Paper start - don't write garbage data to disk if writing serialization fails ++ public static final class RegionFileSizeException extends RuntimeException { ++ ++ public RegionFileSizeException(String message) { ++ super(message); ++ } ++ } ++ // Paper end - don't write garbage data to disk if writing serialization fails + } diff --git a/patches/server/0631-Forward-CraftEntity-in-teleport-command.patch b/patches/server/0631-Forward-CraftEntity-in-teleport-command.patch new file mode 100644 index 0000000000..908c465129 --- /dev/null +++ b/patches/server/0631-Forward-CraftEntity-in-teleport-command.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 4 Dec 2021 17:04:47 -0800 +Subject: [PATCH] Forward CraftEntity in teleport command + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 34cbb7c48535da774527b40f2e99f6f1d31c377d..3df8cfccba9bc4420b37dcbdfc4a12c720b51205 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3480,6 +3480,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public void restoreFrom(Entity original) { ++ // Paper start - Forward CraftEntity in teleport command ++ CraftEntity bukkitEntity = original.bukkitEntity; ++ if (bukkitEntity != null) { ++ bukkitEntity.setHandle(this); ++ this.bukkitEntity = bukkitEntity; ++ } ++ // Paper end - Forward CraftEntity in teleport command + CompoundTag nbttagcompound = original.saveWithoutId(new CompoundTag()); + + nbttagcompound.remove("Dimension"); +@@ -3615,8 +3622,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + entity.restoreFrom(this); + this.removeAfterChangingDimensions(); + // CraftBukkit start - Forward the CraftEntity to the new entity +- this.getBukkitEntity().setHandle(entity); +- entity.bukkitEntity = this.getBukkitEntity(); ++ //this.getBukkitEntity().setHandle(entity); ++ //entity.bukkitEntity = this.getBukkitEntity(); // Paper - forward CraftEntity in teleport command; moved to Entity#restoreFrom + // CraftBukkit end + entity.teleportSetPosition(PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); + if (this.inWorld) world.addDuringTeleport(entity); // CraftBukkit - Don't spawn the new entity if the current entity isn't spawned diff --git a/patches/server/0631-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch b/patches/server/0631-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch deleted file mode 100644 index 80c053acc6..0000000000 --- a/patches/server/0631-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 19 Dec 2021 09:13:41 -0800 -Subject: [PATCH] Only write chunk data to disk if it serializes without - throwing - -This ensures at least a valid version of the chunk exists -on disk, even if outdated - -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index 12b7d50f49a2184aaf220a4a50a137b217c57124..f1237f6fd6414900ffbad0caee31aa83310eeef4 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -442,6 +442,7 @@ public class RegionFile implements AutoCloseable { - - } - -+ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails - private class ChunkBuffer extends ByteArrayOutputStream { - - private final ChunkPos pos; -@@ -455,6 +456,23 @@ public class RegionFile implements AutoCloseable { - super.write(RegionFile.this.version.getId()); - this.pos = chunkcoordintpair; - } -+ // Paper start - don't write garbage data to disk if writing serialization fails -+ @Override -+ public void write(final int b) { -+ if (this.count > MAX_CHUNK_SIZE) { -+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + this.count); -+ } -+ super.write(b); -+ } -+ -+ @Override -+ public void write(final byte[] b, final int off, final int len) { -+ if (this.count + len > MAX_CHUNK_SIZE) { -+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + (this.count + len)); -+ } -+ super.write(b, off, len); -+ } -+ // Paper end - don't write garbage data to disk if writing serialization fails - - public void close() throws IOException { - ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 491035aaefff4ee96435ec5d3f9417e28eae0796..4c1212c6ef48594e766fa9e35a6e15916602d587 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -147,10 +147,17 @@ public final class RegionFileStorage implements AutoCloseable { - - try { - NbtIo.write(nbt, (DataOutput) dataoutputstream); -+ // Paper start - don't write garbage data to disk if writing serialization fails -+ dataoutputstream.close(); // Only write if successful -+ } catch (final RegionFileSizeException e) { -+ attempts = 5; // Don't retry -+ regionfile.clear(pos); -+ throw e; -+ // Paper end - don't write garbage data to disk if writing serialization fails - } catch (Throwable throwable) { - if (dataoutputstream != null) { - try { -- dataoutputstream.close(); -+ //dataoutputstream.close(); // Paper - don't write garbage data to disk if writing serialization fails - } catch (Throwable throwable1) { - throwable.addSuppressed(throwable1); - } -@@ -158,10 +165,7 @@ public final class RegionFileStorage implements AutoCloseable { - - throw throwable; - } -- -- if (dataoutputstream != null) { -- dataoutputstream.close(); -- } -+ // Paper - don't write garbage data to disk if writing serialization fails; move into try block to only write if successfully serialized - } - // Paper start - Chunk save reattempt - return; -@@ -208,4 +212,13 @@ public final class RegionFileStorage implements AutoCloseable { - public RegionStorageInfo info() { - return this.info; - } -+ -+ // Paper start - don't write garbage data to disk if writing serialization fails -+ public static final class RegionFileSizeException extends RuntimeException { -+ -+ public RegionFileSizeException(String message) { -+ super(message); -+ } -+ } -+ // Paper end - don't write garbage data to disk if writing serialization fails - } diff --git a/patches/server/0632-Forward-CraftEntity-in-teleport-command.patch b/patches/server/0632-Forward-CraftEntity-in-teleport-command.patch deleted file mode 100644 index 908c465129..0000000000 --- a/patches/server/0632-Forward-CraftEntity-in-teleport-command.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 4 Dec 2021 17:04:47 -0800 -Subject: [PATCH] Forward CraftEntity in teleport command - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 34cbb7c48535da774527b40f2e99f6f1d31c377d..3df8cfccba9bc4420b37dcbdfc4a12c720b51205 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3480,6 +3480,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public void restoreFrom(Entity original) { -+ // Paper start - Forward CraftEntity in teleport command -+ CraftEntity bukkitEntity = original.bukkitEntity; -+ if (bukkitEntity != null) { -+ bukkitEntity.setHandle(this); -+ this.bukkitEntity = bukkitEntity; -+ } -+ // Paper end - Forward CraftEntity in teleport command - CompoundTag nbttagcompound = original.saveWithoutId(new CompoundTag()); - - nbttagcompound.remove("Dimension"); -@@ -3615,8 +3622,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - entity.restoreFrom(this); - this.removeAfterChangingDimensions(); - // CraftBukkit start - Forward the CraftEntity to the new entity -- this.getBukkitEntity().setHandle(entity); -- entity.bukkitEntity = this.getBukkitEntity(); -+ //this.getBukkitEntity().setHandle(entity); -+ //entity.bukkitEntity = this.getBukkitEntity(); // Paper - forward CraftEntity in teleport command; moved to Entity#restoreFrom - // CraftBukkit end - entity.teleportSetPosition(PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); - if (this.inWorld) world.addDuringTeleport(entity); // CraftBukkit - Don't spawn the new entity if the current entity isn't spawned diff --git a/patches/server/0632-Improve-scoreboard-entries.patch b/patches/server/0632-Improve-scoreboard-entries.patch new file mode 100644 index 0000000000..8acac86ce3 --- /dev/null +++ b/patches/server/0632-Improve-scoreboard-entries.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 4 Nov 2021 12:31:24 -0700 +Subject: [PATCH] Improve scoreboard entries + + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +index da1e4496d78a2c1b258ff8bb316414cb8a662ba2..b36e5574c10e6d70a399e2ac0704fd4f43dbb444 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +@@ -144,6 +144,15 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective + return new CraftScore(this, CraftScoreboard.getScoreHolder(entry)); + } + ++ // Paper start ++ @Override ++ public Score getScoreFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException { ++ Preconditions.checkArgument(entity != null, "Entity cannot be null"); ++ this.checkState(); ++ return new CraftScore(this, ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); ++ } ++ // Paper end ++ + @Override + public void unregister() { + CraftScoreboard scoreboard = this.checkState(); +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java +index c650fc3712de01184509a03f1d1b388859e163d7..253574890a9ed23d38a84680ba1eb221dc72b310 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java +@@ -235,6 +235,26 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard { + this.board.setDisplayObjective(CraftScoreboardTranslations.fromBukkitSlot(slot), null); + } + ++ // Paper start ++ @Override ++ public ImmutableSet getScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException { ++ Preconditions.checkArgument(entity != null, "Entity cannot be null"); ++ return this.getScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); ++ } ++ ++ @Override ++ public void resetScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException { ++ Preconditions.checkArgument(entity != null, "Entity cannot be null"); ++ this.resetScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); ++ } ++ ++ @Override ++ public Team getEntityTeam(org.bukkit.entity.Entity entity) throws IllegalArgumentException { ++ Preconditions.checkArgument(entity != null, "Entity cannot be null"); ++ return this.getEntryTeam(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); ++ } ++ // Paper end ++ + // CraftBukkit method + public Scoreboard getHandle() { + return this.board; +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java +index 7900adb0b158bc17dd792dd082c338547bc1aa0a..27219bf2f16aed64c78623d44c3cc84aa9f47065 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java +@@ -304,6 +304,26 @@ final class CraftTeam extends CraftScoreboardComponent implements Team { + } + } + ++ // Paper start ++ @Override ++ public void addEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException { ++ Preconditions.checkArgument(entity != null, "Entity cannot be null"); ++ this.addEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); ++ } ++ ++ @Override ++ public boolean removeEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException { ++ Preconditions.checkArgument(entity != null, "Entity cannot be null"); ++ return this.removeEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); ++ } ++ ++ @Override ++ public boolean hasEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException { ++ Preconditions.checkArgument(entity != null, "Entity cannot be null"); ++ return this.hasEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); ++ } ++ // Paper end ++ + public static Visibility bukkitToNotch(NameTagVisibility visibility) { + switch (visibility) { + case ALWAYS: diff --git a/patches/server/0633-Entity-powdered-snow-API.patch b/patches/server/0633-Entity-powdered-snow-API.patch new file mode 100644 index 0000000000..09c93986c1 --- /dev/null +++ b/patches/server/0633-Entity-powdered-snow-API.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 24 Oct 2021 20:58:43 -0700 +Subject: [PATCH] Entity powdered snow API + +== AT == +public net.minecraft.world.entity.monster.Skeleton inPowderSnowTime + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 1ed01978611cddb2558e441863dadc468bc07c3d..9693656418210957000add9b6670c4bee67f8462 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1100,6 +1100,13 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + // Paper end - raw entity serialization API + ++ // Paper start - entity powdered snow API ++ @Override ++ public boolean isInPowderedSnow() { ++ return getHandle().isInPowderSnow || getHandle().wasInPowderSnow; // depending on the location in the entity "tick" either could be needed. ++ } ++ // Paper end - entity powdered snow API ++ + // Paper start - missing entity api + @Override + public boolean isInvisible() { // Paper - moved up from LivingEntity +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java +index a0ea54181de6c6685deef265cbe9f66aabbca42b..6f98da9be6aef35e3b5c940188b872459a383c8e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java +@@ -45,4 +45,11 @@ public class CraftSkeleton extends CraftAbstractSkeleton implements Skeleton { + public SkeletonType getSkeletonType() { + return SkeletonType.NORMAL; + } ++ ++ // Paper start ++ @Override ++ public int inPowderedSnowTime() { ++ return getHandle().inPowderSnowTime; ++ } ++ // Paper end + } diff --git a/patches/server/0633-Improve-scoreboard-entries.patch b/patches/server/0633-Improve-scoreboard-entries.patch deleted file mode 100644 index 8acac86ce3..0000000000 --- a/patches/server/0633-Improve-scoreboard-entries.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 4 Nov 2021 12:31:24 -0700 -Subject: [PATCH] Improve scoreboard entries - - -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -index da1e4496d78a2c1b258ff8bb316414cb8a662ba2..b36e5574c10e6d70a399e2ac0704fd4f43dbb444 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -@@ -144,6 +144,15 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective - return new CraftScore(this, CraftScoreboard.getScoreHolder(entry)); - } - -+ // Paper start -+ @Override -+ public Score getScoreFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException { -+ Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ this.checkState(); -+ return new CraftScore(this, ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); -+ } -+ // Paper end -+ - @Override - public void unregister() { - CraftScoreboard scoreboard = this.checkState(); -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java -index c650fc3712de01184509a03f1d1b388859e163d7..253574890a9ed23d38a84680ba1eb221dc72b310 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java -@@ -235,6 +235,26 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard { - this.board.setDisplayObjective(CraftScoreboardTranslations.fromBukkitSlot(slot), null); - } - -+ // Paper start -+ @Override -+ public ImmutableSet getScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException { -+ Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ return this.getScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); -+ } -+ -+ @Override -+ public void resetScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException { -+ Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ this.resetScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); -+ } -+ -+ @Override -+ public Team getEntityTeam(org.bukkit.entity.Entity entity) throws IllegalArgumentException { -+ Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ return this.getEntryTeam(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); -+ } -+ // Paper end -+ - // CraftBukkit method - public Scoreboard getHandle() { - return this.board; -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java -index 7900adb0b158bc17dd792dd082c338547bc1aa0a..27219bf2f16aed64c78623d44c3cc84aa9f47065 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java -@@ -304,6 +304,26 @@ final class CraftTeam extends CraftScoreboardComponent implements Team { - } - } - -+ // Paper start -+ @Override -+ public void addEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException { -+ Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ this.addEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); -+ } -+ -+ @Override -+ public boolean removeEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException { -+ Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ return this.removeEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); -+ } -+ -+ @Override -+ public boolean hasEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException { -+ Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ return this.hasEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); -+ } -+ // Paper end -+ - public static Visibility bukkitToNotch(NameTagVisibility visibility) { - switch (visibility) { - case ALWAYS: diff --git a/patches/server/0634-Add-API-for-item-entity-health.patch b/patches/server/0634-Add-API-for-item-entity-health.patch new file mode 100644 index 0000000000..cd2757b544 --- /dev/null +++ b/patches/server/0634-Add-API-for-item-entity-health.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 28 Aug 2021 09:00:45 -0700 +Subject: [PATCH] Add API for item entity health + +== AT == +public net.minecraft.world.entity.item.ItemEntity health + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +index 4a15c3786edbfeae3367c0b20fb6aee11d62aea6..1a291dd8a287db30e71dcb315599fc4b038764c4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +@@ -98,6 +98,21 @@ public class CraftItem extends CraftEntity implements Item { + public void setWillAge(boolean willAge) { + this.getHandle().age = willAge ? 0 : NO_AGE_TIME; + } ++ ++ @Override ++ public int getHealth() { ++ return this.getHandle().health; ++ } ++ ++ @Override ++ public void setHealth(int health) { ++ if (health <= 0) { ++ this.getHandle().getItem().onDestroyed(this.getHandle()); ++ this.getHandle().discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PLUGIN); ++ } else { ++ this.getHandle().health = health; ++ } ++ } + // Paper end + + @Override diff --git a/patches/server/0634-Entity-powdered-snow-API.patch b/patches/server/0634-Entity-powdered-snow-API.patch deleted file mode 100644 index 09c93986c1..0000000000 --- a/patches/server/0634-Entity-powdered-snow-API.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 24 Oct 2021 20:58:43 -0700 -Subject: [PATCH] Entity powdered snow API - -== AT == -public net.minecraft.world.entity.monster.Skeleton inPowderSnowTime - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 1ed01978611cddb2558e441863dadc468bc07c3d..9693656418210957000add9b6670c4bee67f8462 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1100,6 +1100,13 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - } - // Paper end - raw entity serialization API - -+ // Paper start - entity powdered snow API -+ @Override -+ public boolean isInPowderedSnow() { -+ return getHandle().isInPowderSnow || getHandle().wasInPowderSnow; // depending on the location in the entity "tick" either could be needed. -+ } -+ // Paper end - entity powdered snow API -+ - // Paper start - missing entity api - @Override - public boolean isInvisible() { // Paper - moved up from LivingEntity -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java -index a0ea54181de6c6685deef265cbe9f66aabbca42b..6f98da9be6aef35e3b5c940188b872459a383c8e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java -@@ -45,4 +45,11 @@ public class CraftSkeleton extends CraftAbstractSkeleton implements Skeleton { - public SkeletonType getSkeletonType() { - return SkeletonType.NORMAL; - } -+ -+ // Paper start -+ @Override -+ public int inPowderedSnowTime() { -+ return getHandle().inPowderSnowTime; -+ } -+ // Paper end - } diff --git a/patches/server/0635-Add-API-for-item-entity-health.patch b/patches/server/0635-Add-API-for-item-entity-health.patch deleted file mode 100644 index cd2757b544..0000000000 --- a/patches/server/0635-Add-API-for-item-entity-health.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 28 Aug 2021 09:00:45 -0700 -Subject: [PATCH] Add API for item entity health - -== AT == -public net.minecraft.world.entity.item.ItemEntity health - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -index 4a15c3786edbfeae3367c0b20fb6aee11d62aea6..1a291dd8a287db30e71dcb315599fc4b038764c4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -@@ -98,6 +98,21 @@ public class CraftItem extends CraftEntity implements Item { - public void setWillAge(boolean willAge) { - this.getHandle().age = willAge ? 0 : NO_AGE_TIME; - } -+ -+ @Override -+ public int getHealth() { -+ return this.getHandle().health; -+ } -+ -+ @Override -+ public void setHealth(int health) { -+ if (health <= 0) { -+ this.getHandle().getItem().onDestroyed(this.getHandle()); -+ this.getHandle().discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PLUGIN); -+ } else { -+ this.getHandle().health = health; -+ } -+ } - // Paper end - - @Override diff --git a/patches/server/0635-Configurable-max-block-light-for-monster-spawning.patch b/patches/server/0635-Configurable-max-block-light-for-monster-spawning.patch new file mode 100644 index 0000000000..8c19486a5f --- /dev/null +++ b/patches/server/0635-Configurable-max-block-light-for-monster-spawning.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 16 Dec 2021 09:40:39 +0100 +Subject: [PATCH] Configurable max block light for monster spawning + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java +index c49853f25bdf1fbc7ec9700d421c6ddccabae05f..e2de074bbe7bab0e5a7aecc1fae4c5914a203dd4 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Monster.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java +@@ -92,7 +92,7 @@ public abstract class Monster extends PathfinderMob implements Enemy { + return false; + } else { + DimensionType dimensionType = world.dimensionType(); +- int i = dimensionType.monsterSpawnBlockLightLimit(); ++ int i = world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning + if (i < 15 && world.getBrightness(LightLayer.BLOCK, pos) > i) { + return false; + } else { diff --git a/patches/server/0636-Configurable-max-block-light-for-monster-spawning.patch b/patches/server/0636-Configurable-max-block-light-for-monster-spawning.patch deleted file mode 100644 index 8c19486a5f..0000000000 --- a/patches/server/0636-Configurable-max-block-light-for-monster-spawning.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Thu, 16 Dec 2021 09:40:39 +0100 -Subject: [PATCH] Configurable max block light for monster spawning - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java -index c49853f25bdf1fbc7ec9700d421c6ddccabae05f..e2de074bbe7bab0e5a7aecc1fae4c5914a203dd4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Monster.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java -@@ -92,7 +92,7 @@ public abstract class Monster extends PathfinderMob implements Enemy { - return false; - } else { - DimensionType dimensionType = world.dimensionType(); -- int i = dimensionType.monsterSpawnBlockLightLimit(); -+ int i = world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning - if (i < 15 && world.getBrightness(LightLayer.BLOCK, pos) > i) { - return false; - } else { diff --git a/patches/server/0636-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch b/patches/server/0636-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch new file mode 100644 index 0000000000..b239d74e25 --- /dev/null +++ b/patches/server/0636-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 22 Dec 2021 09:51:48 -0800 +Subject: [PATCH] Fix sticky pistons and BlockPistonRetractEvent + +There is an explicit check in the handling code for empty pistons that +prevents sticky pistons from firing the event. However when we look back +at the history we see that this check was originally added so that ONLY +sticky pistons would fire the retract event. I'm not sure why. +https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1092acbddf07edfa4100bc6824504ac75088e913 + +Over the course of several updates, the meaning of that field appears to +have changed from "is NOT sticky" to "is sticky". So now its having the +opposite effect. Only normal pistons fire the retraction event. And like +all things in CB, it's just been carried around since. + +If we are to believe the history, the correct fix for this issue is to +flip it so it only fires for sticky pistons, but that puts us in a +bind. It's already firing for non-sticky pistons, changing it now would +likely result in breakage. Furthermore, there is little documentation as +to WHY that was ever intended to be the case. + +Instead we opt to remove the check entirely so that the event fires for +all piston types. + +Co-authored-by: Zach Brown +Co-authored-by: Madeline Miller + +diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java +index 4973d75b26880e39d42b5ef533896f43a1f07cba..e841fccb8f298ef692677583b468869f56dc722c 100644 +--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java +@@ -163,15 +163,15 @@ public class PistonBaseBlock extends DirectionalBlock { + } + + // CraftBukkit start +- if (!this.isSticky) { +- org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); +- BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.of(), CraftBlock.notchToBlockFace(enumdirection)); +- world.getCraftServer().getPluginManager().callEvent(event); +- +- if (event.isCancelled()) { +- return; +- } +- } ++ // if (!this.isSticky) { // Paper - Fix sticky pistons and BlockPistonRetractEvent; Move further down ++ // org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); ++ // BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.of(), CraftBlock.notchToBlockFace(enumdirection)); ++ // world.getCraftServer().getPluginManager().callEvent(event); ++ // ++ // if (event.isCancelled()) { ++ // return; ++ // } ++ // } + // PAIL: checkME - what happened to setTypeAndData? + // CraftBukkit end + world.blockEvent(pos, this, b0, enumdirection.get3DDataValue()); +@@ -248,6 +248,13 @@ public class PistonBaseBlock extends DirectionalBlock { + + BlockState iblockdata2 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT); + ++ // Paper start - Fix sticky pistons and BlockPistonRetractEvent; Move empty piston retract call to fix multiple event fires ++ if (!this.isSticky) { ++ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) { ++ return false; ++ } ++ } ++ // Paper end - Fix sticky pistons and BlockPistonRetractEvent + world.setBlock(pos, iblockdata2, 20); + world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); + world.blockUpdated(pos, iblockdata2.getBlock()); +@@ -274,6 +281,13 @@ public class PistonBaseBlock extends DirectionalBlock { + if (type == 1 && !iblockdata3.isAir() && PistonBaseBlock.isPushable(iblockdata3, world, blockposition1, enumdirection.getOpposite(), false, enumdirection) && (iblockdata3.getPistonPushReaction() == PushReaction.NORMAL || iblockdata3.is(Blocks.PISTON) || iblockdata3.is(Blocks.STICKY_PISTON))) { + this.moveBlocks(world, pos, enumdirection, false); + } else { ++ // Paper start - Fix sticky pistons and BlockPistonRetractEvent; fire BlockPistonRetractEvent for sticky pistons retracting nothing (air) ++ if (type == TRIGGER_CONTRACT && iblockdata2.isAir()) { ++ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) { ++ return false; ++ } ++ } ++ // Paper end - Fix sticky pistons and BlockPistonRetractEvent + world.removeBlock(pos.relative(enumdirection), false); + } + } diff --git a/patches/server/0637-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch b/patches/server/0637-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch new file mode 100644 index 0000000000..cfaa295706 --- /dev/null +++ b/patches/server/0637-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 23 Dec 2021 15:32:50 -0600 +Subject: [PATCH] Expose isFuel and canSmelt methods to FurnaceInventory + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java +index 29a8cd7667860c4598a556e6ef3af39c731683db..33c970b467675429ad952925830ed334632fd3b6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java +@@ -40,6 +40,21 @@ public class CraftInventoryFurnace extends CraftInventory implements FurnaceInve + this.setItem(0, stack); + } + ++ // Paper start ++ @Override ++ public boolean isFuel(ItemStack stack) { ++ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorlds().get(0)).getHandle(); ++ return stack != null && !stack.getType().isEmpty() && world.fuelValues().isFuel(CraftItemStack.asNMSCopy(stack)); ++ } ++ ++ @Override ++ public boolean canSmelt(ItemStack stack) { ++ // data packs are always loaded in the main world ++ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorlds().get(0)).getHandle(); ++ return stack != null && !stack.getType().isEmpty() && world.recipeAccess().getRecipeFor(((AbstractFurnaceBlockEntity) this.inventory).recipeType, new net.minecraft.world.item.crafting.SingleRecipeInput(CraftItemStack.asNMSCopy(stack)), world).isPresent(); ++ } ++ // Paper end ++ + @Override + public Furnace getHolder() { + return (Furnace) this.inventory.getOwner(); diff --git a/patches/server/0637-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch b/patches/server/0637-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch deleted file mode 100644 index b239d74e25..0000000000 --- a/patches/server/0637-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 22 Dec 2021 09:51:48 -0800 -Subject: [PATCH] Fix sticky pistons and BlockPistonRetractEvent - -There is an explicit check in the handling code for empty pistons that -prevents sticky pistons from firing the event. However when we look back -at the history we see that this check was originally added so that ONLY -sticky pistons would fire the retract event. I'm not sure why. -https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1092acbddf07edfa4100bc6824504ac75088e913 - -Over the course of several updates, the meaning of that field appears to -have changed from "is NOT sticky" to "is sticky". So now its having the -opposite effect. Only normal pistons fire the retraction event. And like -all things in CB, it's just been carried around since. - -If we are to believe the history, the correct fix for this issue is to -flip it so it only fires for sticky pistons, but that puts us in a -bind. It's already firing for non-sticky pistons, changing it now would -likely result in breakage. Furthermore, there is little documentation as -to WHY that was ever intended to be the case. - -Instead we opt to remove the check entirely so that the event fires for -all piston types. - -Co-authored-by: Zach Brown -Co-authored-by: Madeline Miller - -diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -index 4973d75b26880e39d42b5ef533896f43a1f07cba..e841fccb8f298ef692677583b468869f56dc722c 100644 ---- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -@@ -163,15 +163,15 @@ public class PistonBaseBlock extends DirectionalBlock { - } - - // CraftBukkit start -- if (!this.isSticky) { -- org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); -- BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.of(), CraftBlock.notchToBlockFace(enumdirection)); -- world.getCraftServer().getPluginManager().callEvent(event); -- -- if (event.isCancelled()) { -- return; -- } -- } -+ // if (!this.isSticky) { // Paper - Fix sticky pistons and BlockPistonRetractEvent; Move further down -+ // org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); -+ // BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.of(), CraftBlock.notchToBlockFace(enumdirection)); -+ // world.getCraftServer().getPluginManager().callEvent(event); -+ // -+ // if (event.isCancelled()) { -+ // return; -+ // } -+ // } - // PAIL: checkME - what happened to setTypeAndData? - // CraftBukkit end - world.blockEvent(pos, this, b0, enumdirection.get3DDataValue()); -@@ -248,6 +248,13 @@ public class PistonBaseBlock extends DirectionalBlock { - - BlockState iblockdata2 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT); - -+ // Paper start - Fix sticky pistons and BlockPistonRetractEvent; Move empty piston retract call to fix multiple event fires -+ if (!this.isSticky) { -+ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) { -+ return false; -+ } -+ } -+ // Paper end - Fix sticky pistons and BlockPistonRetractEvent - world.setBlock(pos, iblockdata2, 20); - world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); - world.blockUpdated(pos, iblockdata2.getBlock()); -@@ -274,6 +281,13 @@ public class PistonBaseBlock extends DirectionalBlock { - if (type == 1 && !iblockdata3.isAir() && PistonBaseBlock.isPushable(iblockdata3, world, blockposition1, enumdirection.getOpposite(), false, enumdirection) && (iblockdata3.getPistonPushReaction() == PushReaction.NORMAL || iblockdata3.is(Blocks.PISTON) || iblockdata3.is(Blocks.STICKY_PISTON))) { - this.moveBlocks(world, pos, enumdirection, false); - } else { -+ // Paper start - Fix sticky pistons and BlockPistonRetractEvent; fire BlockPistonRetractEvent for sticky pistons retracting nothing (air) -+ if (type == TRIGGER_CONTRACT && iblockdata2.isAir()) { -+ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) { -+ return false; -+ } -+ } -+ // Paper end - Fix sticky pistons and BlockPistonRetractEvent - world.removeBlock(pos.relative(enumdirection), false); - } - } diff --git a/patches/server/0638-Bucketable-API.patch b/patches/server/0638-Bucketable-API.patch new file mode 100644 index 0000000000..274ccde059 --- /dev/null +++ b/patches/server/0638-Bucketable-API.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 26 Dec 2021 14:03:17 -0500 +Subject: [PATCH] Bucketable API + + +diff --git a/src/main/java/io/papermc/paper/entity/PaperBucketable.java b/src/main/java/io/papermc/paper/entity/PaperBucketable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d3fc2e5db9f3c20120b403bf03c3c340b9956cbd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/PaperBucketable.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.entity; ++ ++import org.bukkit.Sound; ++import org.bukkit.craftbukkit.CraftSound; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.inventory.ItemStack; ++ ++public interface PaperBucketable extends Bucketable { ++ ++ net.minecraft.world.entity.animal.Bucketable getHandle(); ++ ++ @Override ++ default boolean isFromBucket() { ++ return this.getHandle().fromBucket(); ++ } ++ ++ @Override ++ default void setFromBucket(boolean fromBucket) { ++ this.getHandle().setFromBucket(fromBucket); ++ } ++ ++ @Override ++ default ItemStack getBaseBucketItem() { ++ return CraftItemStack.asBukkitCopy(this.getHandle().getBucketItemStack()); ++ } ++ ++ @Override ++ default Sound getPickupSound() { ++ return CraftSound.minecraftToBukkit(this.getHandle().getPickupSound()); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java +index e730292edca4624400bdb89d555922c5f61db7a5..cbfca242f820d238b112f8ce64e9de8398c48a1c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java +@@ -4,7 +4,7 @@ import com.google.common.base.Preconditions; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Axolotl; + +-public class CraftAxolotl extends CraftAnimals implements Axolotl { ++public class CraftAxolotl extends CraftAnimals implements Axolotl, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API + + public CraftAxolotl(CraftServer server, net.minecraft.world.entity.animal.axolotl.Axolotl entity) { + super(server, entity); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java +index da5150f4ca0397bf10053aab0c3ff18af5bc3f3c..eb10f94d5ed8ca89d3786138647dd43357609a6c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java +@@ -4,7 +4,7 @@ import net.minecraft.world.entity.animal.AbstractFish; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Fish; + +-public class CraftFish extends CraftWaterMob implements Fish { ++public class CraftFish extends CraftWaterMob implements Fish, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API + + public CraftFish(CraftServer server, AbstractFish entity) { + super(server, entity); diff --git a/patches/server/0638-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch b/patches/server/0638-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch deleted file mode 100644 index cfaa295706..0000000000 --- a/patches/server/0638-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 23 Dec 2021 15:32:50 -0600 -Subject: [PATCH] Expose isFuel and canSmelt methods to FurnaceInventory - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java -index 29a8cd7667860c4598a556e6ef3af39c731683db..33c970b467675429ad952925830ed334632fd3b6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java -@@ -40,6 +40,21 @@ public class CraftInventoryFurnace extends CraftInventory implements FurnaceInve - this.setItem(0, stack); - } - -+ // Paper start -+ @Override -+ public boolean isFuel(ItemStack stack) { -+ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorlds().get(0)).getHandle(); -+ return stack != null && !stack.getType().isEmpty() && world.fuelValues().isFuel(CraftItemStack.asNMSCopy(stack)); -+ } -+ -+ @Override -+ public boolean canSmelt(ItemStack stack) { -+ // data packs are always loaded in the main world -+ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorlds().get(0)).getHandle(); -+ return stack != null && !stack.getType().isEmpty() && world.recipeAccess().getRecipeFor(((AbstractFurnaceBlockEntity) this.inventory).recipeType, new net.minecraft.world.item.crafting.SingleRecipeInput(CraftItemStack.asNMSCopy(stack)), world).isPresent(); -+ } -+ // Paper end -+ - @Override - public Furnace getHolder() { - return (Furnace) this.inventory.getOwner(); diff --git a/patches/server/0639-Bucketable-API.patch b/patches/server/0639-Bucketable-API.patch deleted file mode 100644 index 274ccde059..0000000000 --- a/patches/server/0639-Bucketable-API.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 26 Dec 2021 14:03:17 -0500 -Subject: [PATCH] Bucketable API - - -diff --git a/src/main/java/io/papermc/paper/entity/PaperBucketable.java b/src/main/java/io/papermc/paper/entity/PaperBucketable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d3fc2e5db9f3c20120b403bf03c3c340b9956cbd ---- /dev/null -+++ b/src/main/java/io/papermc/paper/entity/PaperBucketable.java -@@ -0,0 +1,31 @@ -+package io.papermc.paper.entity; -+ -+import org.bukkit.Sound; -+import org.bukkit.craftbukkit.CraftSound; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.inventory.ItemStack; -+ -+public interface PaperBucketable extends Bucketable { -+ -+ net.minecraft.world.entity.animal.Bucketable getHandle(); -+ -+ @Override -+ default boolean isFromBucket() { -+ return this.getHandle().fromBucket(); -+ } -+ -+ @Override -+ default void setFromBucket(boolean fromBucket) { -+ this.getHandle().setFromBucket(fromBucket); -+ } -+ -+ @Override -+ default ItemStack getBaseBucketItem() { -+ return CraftItemStack.asBukkitCopy(this.getHandle().getBucketItemStack()); -+ } -+ -+ @Override -+ default Sound getPickupSound() { -+ return CraftSound.minecraftToBukkit(this.getHandle().getPickupSound()); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java -index e730292edca4624400bdb89d555922c5f61db7a5..cbfca242f820d238b112f8ce64e9de8398c48a1c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java -@@ -4,7 +4,7 @@ import com.google.common.base.Preconditions; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Axolotl; - --public class CraftAxolotl extends CraftAnimals implements Axolotl { -+public class CraftAxolotl extends CraftAnimals implements Axolotl, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API - - public CraftAxolotl(CraftServer server, net.minecraft.world.entity.animal.axolotl.Axolotl entity) { - super(server, entity); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java -index da5150f4ca0397bf10053aab0c3ff18af5bc3f3c..eb10f94d5ed8ca89d3786138647dd43357609a6c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java -@@ -4,7 +4,7 @@ import net.minecraft.world.entity.animal.AbstractFish; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Fish; - --public class CraftFish extends CraftWaterMob implements Fish { -+public class CraftFish extends CraftWaterMob implements Fish, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API - - public CraftFish(CraftServer server, AbstractFish entity) { - super(server, entity); diff --git a/patches/server/0639-Validate-usernames.patch b/patches/server/0639-Validate-usernames.patch new file mode 100644 index 0000000000..89dbf3385d --- /dev/null +++ b/patches/server/0639-Validate-usernames.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 1 Jan 2022 05:19:37 -0800 +Subject: [PATCH] Validate usernames + + +diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index 1e4b288f20153ce0c91fabf164c5c8320c90ba7d..cb5dd77892283a1aaec45434fb99bb7f08ee5394 100644 +--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -90,6 +90,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + private final String serverId; + private final boolean transferred; + private ServerPlayer player; // CraftBukkit ++ public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding + + public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { + this.state = ServerLoginPacketListenerImpl.State.HELLO; +@@ -171,7 +172,13 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + @Override + public void handleHello(ServerboundHelloPacket packet) { + Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]); +- Validate.validState(StringUtil.isValidPlayerName(packet.name()), "Invalid characters in username", new Object[0]); ++ // Paper start - Validate usernames ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ++ && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation ++ && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation) { ++ Validate.validState(StringUtil.isReasonablePlayerName(packet.name()), "Invalid characters in username", new Object[0]); ++ } ++ // Paper end - Validate usernames + this.requestedUsername = packet.name(); + GameProfile gameprofile = this.server.getSingleplayerProfile(); + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index dd7b19a7762b91a8b27717098cebd2c48cb96f68..2497aeb46ff4188948e9253c21d83a218fd73e85 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -627,7 +627,7 @@ public abstract class PlayerList { + + for (int i = 0; i < this.players.size(); ++i) { + entityplayer = (ServerPlayer) this.players.get(i); +- if (entityplayer.getUUID().equals(uuid)) { ++ if (entityplayer.getUUID().equals(uuid) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameprofile.getName()))) { // Paper - validate usernames + list.add(entityplayer); + } + } +diff --git a/src/main/java/net/minecraft/util/StringUtil.java b/src/main/java/net/minecraft/util/StringUtil.java +index e588bd7ef0616dc88ce4c0feeeabadc29dcaa550..6c33002dc8bbb3759c3156302ab7d1f26ce5e8ee 100644 +--- a/src/main/java/net/minecraft/util/StringUtil.java ++++ b/src/main/java/net/minecraft/util/StringUtil.java +@@ -67,6 +67,25 @@ public class StringUtil { + return name.length() <= 16 && name.chars().filter(c -> c <= 32 || c >= 127).findAny().isEmpty(); + } + ++ // Paper start - Username validation ++ public static boolean isReasonablePlayerName(final String name) { ++ if (name.isEmpty() || name.length() > 16) { ++ return false; ++ } ++ ++ for (int i = 0, len = name.length(); i < len; ++i) { ++ final char c = name.charAt(i); ++ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_' || c == '.')) { ++ continue; ++ } ++ ++ return false; ++ } ++ ++ return true; ++ } ++ // Paper end - Username validation ++ + public static String filterText(String string) { + return filterText(string, false); + } diff --git a/patches/server/0640-Make-water-animal-spawn-height-configurable.patch b/patches/server/0640-Make-water-animal-spawn-height-configurable.patch new file mode 100644 index 0000000000..341b55b1f6 --- /dev/null +++ b/patches/server/0640-Make-water-animal-spawn-height-configurable.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brokkonaut +Date: Sat, 18 Dec 2021 08:26:55 +0100 +Subject: [PATCH] Make water animal spawn height configurable + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java +index 6a8a90059dcc524a0724264c8d604bf39228a650..8c4532a250f8679d729a35c17e9b5bd339264450 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java +@@ -70,6 +70,10 @@ public abstract class WaterAnimal extends PathfinderMob { + ) { + int i = world.getSeaLevel(); + int j = i - 13; ++ // Paper start - Make water animal spawn height configurable ++ i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i); ++ j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j); ++ // Paper end - Make water animal spawn height configurable + return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); + } + } diff --git a/patches/server/0640-Validate-usernames.patch b/patches/server/0640-Validate-usernames.patch deleted file mode 100644 index 74facbf238..0000000000 --- a/patches/server/0640-Validate-usernames.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 1 Jan 2022 05:19:37 -0800 -Subject: [PATCH] Validate usernames - - -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 1e4b288f20153ce0c91fabf164c5c8320c90ba7d..cb5dd77892283a1aaec45434fb99bb7f08ee5394 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -90,6 +90,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - private final String serverId; - private final boolean transferred; - private ServerPlayer player; // CraftBukkit -+ public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding - - public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { - this.state = ServerLoginPacketListenerImpl.State.HELLO; -@@ -171,7 +172,13 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - @Override - public void handleHello(ServerboundHelloPacket packet) { - Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]); -- Validate.validState(StringUtil.isValidPlayerName(packet.name()), "Invalid characters in username", new Object[0]); -+ // Paper start - Validate usernames -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() -+ && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation -+ && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation) { -+ Validate.validState(StringUtil.isReasonablePlayerName(packet.name()), "Invalid characters in username", new Object[0]); -+ } -+ // Paper end - Validate usernames - this.requestedUsername = packet.name(); - GameProfile gameprofile = this.server.getSingleplayerProfile(); - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 1b6540ae28d73501c59581b1864f0e01ab53e365..f34cad30c982f2bb563f0deab030111720858fa8 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -628,7 +628,7 @@ public abstract class PlayerList { - - for (int i = 0; i < this.players.size(); ++i) { - entityplayer = (ServerPlayer) this.players.get(i); -- if (entityplayer.getUUID().equals(uuid)) { -+ if (entityplayer.getUUID().equals(uuid) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameprofile.getName()))) { // Paper - validate usernames - list.add(entityplayer); - } - } -diff --git a/src/main/java/net/minecraft/util/StringUtil.java b/src/main/java/net/minecraft/util/StringUtil.java -index e588bd7ef0616dc88ce4c0feeeabadc29dcaa550..6c33002dc8bbb3759c3156302ab7d1f26ce5e8ee 100644 ---- a/src/main/java/net/minecraft/util/StringUtil.java -+++ b/src/main/java/net/minecraft/util/StringUtil.java -@@ -67,6 +67,25 @@ public class StringUtil { - return name.length() <= 16 && name.chars().filter(c -> c <= 32 || c >= 127).findAny().isEmpty(); - } - -+ // Paper start - Username validation -+ public static boolean isReasonablePlayerName(final String name) { -+ if (name.isEmpty() || name.length() > 16) { -+ return false; -+ } -+ -+ for (int i = 0, len = name.length(); i < len; ++i) { -+ final char c = name.charAt(i); -+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_' || c == '.')) { -+ continue; -+ } -+ -+ return false; -+ } -+ -+ return true; -+ } -+ // Paper end - Username validation -+ - public static String filterText(String string) { - return filterText(string, false); - } diff --git a/patches/server/0641-Expose-vanilla-BiomeProvider-from-WorldInfo.patch b/patches/server/0641-Expose-vanilla-BiomeProvider-from-WorldInfo.patch new file mode 100644 index 0000000000..b09fd4e699 --- /dev/null +++ b/patches/server/0641-Expose-vanilla-BiomeProvider-from-WorldInfo.patch @@ -0,0 +1,177 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Thu, 6 Jan 2022 15:59:06 -0800 +Subject: [PATCH] Expose vanilla BiomeProvider from WorldInfo + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 7ab9a9c04f94a68dccb5ec9bfc8171bfc02927a2..8cbc8eeaa8719f8bb136543e80ec85248c90e154 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -626,7 +626,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(iworlddataserver)); + LevelStem worlddimension = (LevelStem) dimensions.getValue(dimensionKey); + +- org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value()); ++ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value(), worlddimension.generator(), this.registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo + if (biomeProvider == null && gen != null) { + biomeProvider = gen.getDefaultBiomeProvider(worldInfo); + } +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 3b3024fcf39266cc6ae61fb77dbffb391dc96c92..2d77e9526917a83987ae0486a669538d5417b781 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -357,7 +357,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.serverLevelData.setWorld(this); + + if (biomeProvider != null) { +- BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME)); ++ BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME), chunkgenerator.getBiomeSource()); // Paper - add vanillaBiomeProvider + if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) { + chunkgenerator = new NoiseBasedChunkGenerator(worldChunkManager, cga.settings); + } else if (chunkgenerator instanceof FlatLevelSource cpf) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 1c72862b3167acc05f06b44cd9a0929ad8d2b9c8..6d32505266fef119289bcf6761c1948368238eb9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1310,7 +1310,7 @@ public final class CraftServer implements Server { + List list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata)); + LevelStem worlddimension = iregistry.getValue(actualDimension); + +- WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), worlddimension.type().value()); ++ WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), worlddimension.type().value(), worlddimension.generator(), this.getHandle().getServer().registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo + if (biomeProvider == null && generator != null) { + biomeProvider = generator.getDefaultBiomeProvider(worldInfo); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 5050c9a9d5369a829f5b47a56b7621de05c9a6de..0ff12d4e74c14b2b0ecf06d720c5e06edb35fcdb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -216,6 +216,39 @@ public class CraftWorld extends CraftRegionAccessor implements World { + public int getPlayerCount() { + return world.players().size(); + } ++ ++ @Override ++ public BiomeProvider vanillaBiomeProvider() { ++ net.minecraft.server.level.ServerChunkCache serverCache = this.getHandle().chunkSource; ++ ++ final net.minecraft.world.level.chunk.ChunkGenerator gen = serverCache.getGenerator(); ++ net.minecraft.world.level.biome.BiomeSource biomeSource; ++ if (gen instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator custom) { ++ biomeSource = custom.getDelegate().getBiomeSource(); ++ } else { ++ biomeSource = gen.getBiomeSource(); ++ } ++ if (biomeSource instanceof org.bukkit.craftbukkit.generator.CustomWorldChunkManager customBiomeSource) { ++ biomeSource = customBiomeSource.vanillaBiomeSource; ++ } ++ final net.minecraft.world.level.biome.BiomeSource finalBiomeSource = biomeSource; ++ final net.minecraft.world.level.biome.Climate.Sampler sampler = serverCache.randomState().sampler(); ++ ++ final List possibleBiomes = finalBiomeSource.possibleBiomes().stream() ++ .map(CraftBiome::minecraftHolderToBukkit) ++ .toList(); ++ return new BiomeProvider() { ++ @Override ++ public Biome getBiome(final org.bukkit.generator.WorldInfo worldInfo, final int x, final int y, final int z) { ++ return CraftBiome.minecraftHolderToBukkit(finalBiomeSource.getNoiseBiome(x >> 2, y >> 2, z >> 2, sampler)); ++ } ++ ++ @Override ++ public List getBiomes(final org.bukkit.generator.WorldInfo worldInfo) { ++ return possibleBiomes; ++ } ++ }; ++ } + // Paper end + + private static final Random rand = new Random(); +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java +index 5d655d6cd3e23e0287069f8bdf77601487e862fd..c81455a4ee9a3185f125ebf8cec325f4ed2e501d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java +@@ -17,8 +17,14 @@ public class CraftWorldInfo implements WorldInfo { + private final long seed; + private final int minHeight; + private final int maxHeight; ++ // Paper start ++ private final net.minecraft.world.level.chunk.ChunkGenerator vanillaChunkGenerator; ++ private final net.minecraft.core.RegistryAccess.Frozen registryAccess; + +- public CraftWorldInfo(ServerLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager) { ++ public CraftWorldInfo(PrimaryLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager, net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator, net.minecraft.core.RegistryAccess.Frozen registryAccess) { ++ this.registryAccess = registryAccess; ++ this.vanillaChunkGenerator = chunkGenerator; ++ // Paper end + this.name = worldDataServer.getLevelName(); + this.uuid = WorldUUID.getUUID(session.levelDirectory.path().toFile()); + this.environment = environment; +@@ -27,15 +33,6 @@ public class CraftWorldInfo implements WorldInfo { + this.maxHeight = dimensionManager.minY() + dimensionManager.height(); + } + +- public CraftWorldInfo(String name, UUID uuid, World.Environment environment, long seed, int minHeight, int maxHeight) { +- this.name = name; +- this.uuid = uuid; +- this.environment = environment; +- this.seed = seed; +- this.minHeight = minHeight; +- this.maxHeight = maxHeight; +- } +- + @Override + public String getName() { + return this.name; +@@ -65,4 +62,34 @@ public class CraftWorldInfo implements WorldInfo { + public int getMaxHeight() { + return this.maxHeight; + } ++ ++ // Paper start ++ @Override ++ public org.bukkit.generator.BiomeProvider vanillaBiomeProvider() { ++ final net.minecraft.world.level.levelgen.RandomState randomState; ++ if (vanillaChunkGenerator instanceof net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator noiseBasedChunkGenerator) { ++ randomState = net.minecraft.world.level.levelgen.RandomState.create(noiseBasedChunkGenerator.generatorSettings().value(), ++ registryAccess.lookupOrThrow(net.minecraft.core.registries.Registries.NOISE), getSeed()); ++ } else { ++ randomState = net.minecraft.world.level.levelgen.RandomState.create(net.minecraft.world.level.levelgen.NoiseGeneratorSettings.dummy(), ++ registryAccess.lookupOrThrow(net.minecraft.core.registries.Registries.NOISE), getSeed()); ++ } ++ ++ final java.util.List possibleBiomes = CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().possibleBiomes().stream() ++ .map(biome -> org.bukkit.craftbukkit.block.CraftBiome.minecraftHolderToBukkit(biome)) ++ .toList(); ++ return new org.bukkit.generator.BiomeProvider() { ++ @Override ++ public org.bukkit.block.Biome getBiome(final WorldInfo worldInfo, final int x, final int y, final int z) { ++ return org.bukkit.craftbukkit.block.CraftBiome.minecraftHolderToBukkit( ++ CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().getNoiseBiome(x >> 2, y >> 2, z >> 2, randomState.sampler())); ++ } ++ ++ @Override ++ public java.util.List getBiomes(final org.bukkit.generator.WorldInfo worldInfo) { ++ return possibleBiomes; ++ } ++ }; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java +index 0063c4c17d05a77adf81164fb9307a29860cbe12..0bac128d6faff0063b03f595b82deea78d1ae161 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java +@@ -31,7 +31,11 @@ public class CustomWorldChunkManager extends BiomeSource { + return biomeBases; + } + +- public CustomWorldChunkManager(WorldInfo worldInfo, BiomeProvider biomeProvider, Registry registry) { ++ // Paper start - add vanillaBiomeProvider ++ public final BiomeSource vanillaBiomeSource; ++ public CustomWorldChunkManager(WorldInfo worldInfo, BiomeProvider biomeProvider, Registry registry, BiomeSource vanillaBiomeSource) { ++ this.vanillaBiomeSource = vanillaBiomeSource; ++ // Paper end - add vanillaBiomeProvider + this.worldInfo = worldInfo; + this.biomeProvider = biomeProvider; + this.registry = registry; diff --git a/patches/server/0641-Make-water-animal-spawn-height-configurable.patch b/patches/server/0641-Make-water-animal-spawn-height-configurable.patch deleted file mode 100644 index 341b55b1f6..0000000000 --- a/patches/server/0641-Make-water-animal-spawn-height-configurable.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brokkonaut -Date: Sat, 18 Dec 2021 08:26:55 +0100 -Subject: [PATCH] Make water animal spawn height configurable - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -index 6a8a90059dcc524a0724264c8d604bf39228a650..8c4532a250f8679d729a35c17e9b5bd339264450 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -@@ -70,6 +70,10 @@ public abstract class WaterAnimal extends PathfinderMob { - ) { - int i = world.getSeaLevel(); - int j = i - 13; -+ // Paper start - Make water animal spawn height configurable -+ i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i); -+ j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j); -+ // Paper end - Make water animal spawn height configurable - return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); - } - } diff --git a/patches/server/0642-Add-config-option-for-worlds-affected-by-time-cmd.patch b/patches/server/0642-Add-config-option-for-worlds-affected-by-time-cmd.patch new file mode 100644 index 0000000000..156eacada9 --- /dev/null +++ b/patches/server/0642-Add-config-option-for-worlds-affected-by-time-cmd.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 2 Jan 2022 22:34:51 -0800 +Subject: [PATCH] Add config option for worlds affected by time cmd + + +diff --git a/src/main/java/net/minecraft/server/commands/TimeCommand.java b/src/main/java/net/minecraft/server/commands/TimeCommand.java +index db9317f813244c3cd895bdf9c4eb2218f68c4f1d..44fcd43a466fb47d31ab05e44bafbef3c4cae63f 100644 +--- a/src/main/java/net/minecraft/server/commands/TimeCommand.java ++++ b/src/main/java/net/minecraft/server/commands/TimeCommand.java +@@ -53,7 +53,7 @@ public class TimeCommand { + } + + public static int setTime(CommandSourceStack source, int time) { +- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in ++ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change + + while (iterator.hasNext()) { + ServerLevel worldserver = (ServerLevel) iterator.next(); +@@ -74,7 +74,7 @@ public class TimeCommand { + } + + public static int addTime(CommandSourceStack source, int time) { +- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in ++ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change + + while (iterator.hasNext()) { + ServerLevel worldserver = (ServerLevel) iterator.next(); diff --git a/patches/server/0642-Expose-vanilla-BiomeProvider-from-WorldInfo.patch b/patches/server/0642-Expose-vanilla-BiomeProvider-from-WorldInfo.patch deleted file mode 100644 index ecf4c51174..0000000000 --- a/patches/server/0642-Expose-vanilla-BiomeProvider-from-WorldInfo.patch +++ /dev/null @@ -1,177 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Thu, 6 Jan 2022 15:59:06 -0800 -Subject: [PATCH] Expose vanilla BiomeProvider from WorldInfo - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index f191209b9a1d581235a638bd89ee2eb4050d5cb0..ac9b2eb3fadc2aa6f740a53b13029aa65724a37a 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -627,7 +627,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(iworlddataserver)); - LevelStem worlddimension = (LevelStem) dimensions.getValue(dimensionKey); - -- org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value()); -+ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value(), worlddimension.generator(), this.registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo - if (biomeProvider == null && gen != null) { - biomeProvider = gen.getDefaultBiomeProvider(worldInfo); - } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 3ca2c0d937dc840ac64fb1efd73dbc5b045bc77d..9ac6d2e87bbad00c9b97028b0e9c2a42cf29801b 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -359,7 +359,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.serverLevelData.setWorld(this); - - if (biomeProvider != null) { -- BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME)); -+ BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME), chunkgenerator.getBiomeSource()); // Paper - add vanillaBiomeProvider - if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) { - chunkgenerator = new NoiseBasedChunkGenerator(worldChunkManager, cga.settings); - } else if (chunkgenerator instanceof FlatLevelSource cpf) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index f69504676d2f48f3778f489ec1e08e2b3dec85cc..d30c1e853bb2e27922a00d890dffca153cdcbe97 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1311,7 +1311,7 @@ public final class CraftServer implements Server { - List list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata)); - LevelStem worlddimension = iregistry.getValue(actualDimension); - -- WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), worlddimension.type().value()); -+ WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), worlddimension.type().value(), worlddimension.generator(), this.getHandle().getServer().registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo - if (biomeProvider == null && generator != null) { - biomeProvider = generator.getDefaultBiomeProvider(worldInfo); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 5050c9a9d5369a829f5b47a56b7621de05c9a6de..0ff12d4e74c14b2b0ecf06d720c5e06edb35fcdb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -216,6 +216,39 @@ public class CraftWorld extends CraftRegionAccessor implements World { - public int getPlayerCount() { - return world.players().size(); - } -+ -+ @Override -+ public BiomeProvider vanillaBiomeProvider() { -+ net.minecraft.server.level.ServerChunkCache serverCache = this.getHandle().chunkSource; -+ -+ final net.minecraft.world.level.chunk.ChunkGenerator gen = serverCache.getGenerator(); -+ net.minecraft.world.level.biome.BiomeSource biomeSource; -+ if (gen instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator custom) { -+ biomeSource = custom.getDelegate().getBiomeSource(); -+ } else { -+ biomeSource = gen.getBiomeSource(); -+ } -+ if (biomeSource instanceof org.bukkit.craftbukkit.generator.CustomWorldChunkManager customBiomeSource) { -+ biomeSource = customBiomeSource.vanillaBiomeSource; -+ } -+ final net.minecraft.world.level.biome.BiomeSource finalBiomeSource = biomeSource; -+ final net.minecraft.world.level.biome.Climate.Sampler sampler = serverCache.randomState().sampler(); -+ -+ final List possibleBiomes = finalBiomeSource.possibleBiomes().stream() -+ .map(CraftBiome::minecraftHolderToBukkit) -+ .toList(); -+ return new BiomeProvider() { -+ @Override -+ public Biome getBiome(final org.bukkit.generator.WorldInfo worldInfo, final int x, final int y, final int z) { -+ return CraftBiome.minecraftHolderToBukkit(finalBiomeSource.getNoiseBiome(x >> 2, y >> 2, z >> 2, sampler)); -+ } -+ -+ @Override -+ public List getBiomes(final org.bukkit.generator.WorldInfo worldInfo) { -+ return possibleBiomes; -+ } -+ }; -+ } - // Paper end - - private static final Random rand = new Random(); -diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java -index 5d655d6cd3e23e0287069f8bdf77601487e862fd..c81455a4ee9a3185f125ebf8cec325f4ed2e501d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java -+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java -@@ -17,8 +17,14 @@ public class CraftWorldInfo implements WorldInfo { - private final long seed; - private final int minHeight; - private final int maxHeight; -+ // Paper start -+ private final net.minecraft.world.level.chunk.ChunkGenerator vanillaChunkGenerator; -+ private final net.minecraft.core.RegistryAccess.Frozen registryAccess; - -- public CraftWorldInfo(ServerLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager) { -+ public CraftWorldInfo(PrimaryLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager, net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator, net.minecraft.core.RegistryAccess.Frozen registryAccess) { -+ this.registryAccess = registryAccess; -+ this.vanillaChunkGenerator = chunkGenerator; -+ // Paper end - this.name = worldDataServer.getLevelName(); - this.uuid = WorldUUID.getUUID(session.levelDirectory.path().toFile()); - this.environment = environment; -@@ -27,15 +33,6 @@ public class CraftWorldInfo implements WorldInfo { - this.maxHeight = dimensionManager.minY() + dimensionManager.height(); - } - -- public CraftWorldInfo(String name, UUID uuid, World.Environment environment, long seed, int minHeight, int maxHeight) { -- this.name = name; -- this.uuid = uuid; -- this.environment = environment; -- this.seed = seed; -- this.minHeight = minHeight; -- this.maxHeight = maxHeight; -- } -- - @Override - public String getName() { - return this.name; -@@ -65,4 +62,34 @@ public class CraftWorldInfo implements WorldInfo { - public int getMaxHeight() { - return this.maxHeight; - } -+ -+ // Paper start -+ @Override -+ public org.bukkit.generator.BiomeProvider vanillaBiomeProvider() { -+ final net.minecraft.world.level.levelgen.RandomState randomState; -+ if (vanillaChunkGenerator instanceof net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator noiseBasedChunkGenerator) { -+ randomState = net.minecraft.world.level.levelgen.RandomState.create(noiseBasedChunkGenerator.generatorSettings().value(), -+ registryAccess.lookupOrThrow(net.minecraft.core.registries.Registries.NOISE), getSeed()); -+ } else { -+ randomState = net.minecraft.world.level.levelgen.RandomState.create(net.minecraft.world.level.levelgen.NoiseGeneratorSettings.dummy(), -+ registryAccess.lookupOrThrow(net.minecraft.core.registries.Registries.NOISE), getSeed()); -+ } -+ -+ final java.util.List possibleBiomes = CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().possibleBiomes().stream() -+ .map(biome -> org.bukkit.craftbukkit.block.CraftBiome.minecraftHolderToBukkit(biome)) -+ .toList(); -+ return new org.bukkit.generator.BiomeProvider() { -+ @Override -+ public org.bukkit.block.Biome getBiome(final WorldInfo worldInfo, final int x, final int y, final int z) { -+ return org.bukkit.craftbukkit.block.CraftBiome.minecraftHolderToBukkit( -+ CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().getNoiseBiome(x >> 2, y >> 2, z >> 2, randomState.sampler())); -+ } -+ -+ @Override -+ public java.util.List getBiomes(final org.bukkit.generator.WorldInfo worldInfo) { -+ return possibleBiomes; -+ } -+ }; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java -index 0063c4c17d05a77adf81164fb9307a29860cbe12..0bac128d6faff0063b03f595b82deea78d1ae161 100644 ---- a/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java -+++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java -@@ -31,7 +31,11 @@ public class CustomWorldChunkManager extends BiomeSource { - return biomeBases; - } - -- public CustomWorldChunkManager(WorldInfo worldInfo, BiomeProvider biomeProvider, Registry registry) { -+ // Paper start - add vanillaBiomeProvider -+ public final BiomeSource vanillaBiomeSource; -+ public CustomWorldChunkManager(WorldInfo worldInfo, BiomeProvider biomeProvider, Registry registry, BiomeSource vanillaBiomeSource) { -+ this.vanillaBiomeSource = vanillaBiomeSource; -+ // Paper end - add vanillaBiomeProvider - this.worldInfo = worldInfo; - this.biomeProvider = biomeProvider; - this.registry = registry; diff --git a/patches/server/0643-Add-config-option-for-worlds-affected-by-time-cmd.patch b/patches/server/0643-Add-config-option-for-worlds-affected-by-time-cmd.patch deleted file mode 100644 index 156eacada9..0000000000 --- a/patches/server/0643-Add-config-option-for-worlds-affected-by-time-cmd.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 2 Jan 2022 22:34:51 -0800 -Subject: [PATCH] Add config option for worlds affected by time cmd - - -diff --git a/src/main/java/net/minecraft/server/commands/TimeCommand.java b/src/main/java/net/minecraft/server/commands/TimeCommand.java -index db9317f813244c3cd895bdf9c4eb2218f68c4f1d..44fcd43a466fb47d31ab05e44bafbef3c4cae63f 100644 ---- a/src/main/java/net/minecraft/server/commands/TimeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/TimeCommand.java -@@ -53,7 +53,7 @@ public class TimeCommand { - } - - public static int setTime(CommandSourceStack source, int time) { -- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in -+ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change - - while (iterator.hasNext()) { - ServerLevel worldserver = (ServerLevel) iterator.next(); -@@ -74,7 +74,7 @@ public class TimeCommand { - } - - public static int addTime(CommandSourceStack source, int time) { -- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in -+ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change - - while (iterator.hasNext()) { - ServerLevel worldserver = (ServerLevel) iterator.next(); diff --git a/patches/server/0643-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch b/patches/server/0643-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch new file mode 100644 index 0000000000..be0eedab93 --- /dev/null +++ b/patches/server/0643-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: u9g +Date: Mon, 3 Jan 2022 23:32:42 -0500 +Subject: [PATCH] Add missing IAE check for PersistentDataContainer#has + + +diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java +index 3001bb0e3d4af9b16645a0136093db594b89ab01..984e988a47aa55a3fd92198e379d0f92f511daef 100644 +--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java ++++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java +@@ -57,6 +57,7 @@ public class CraftPersistentDataContainer implements PersistentDataContainer { + + @Override + public boolean has(NamespacedKey key) { ++ Preconditions.checkArgument(key != null, "The provided key for the custom value was null"); // Paper + return this.customDataTags.get(key.toString()) != null; + } + diff --git a/patches/server/0644-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch b/patches/server/0644-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch deleted file mode 100644 index be0eedab93..0000000000 --- a/patches/server/0644-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: u9g -Date: Mon, 3 Jan 2022 23:32:42 -0500 -Subject: [PATCH] Add missing IAE check for PersistentDataContainer#has - - -diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -index 3001bb0e3d4af9b16645a0136093db594b89ab01..984e988a47aa55a3fd92198e379d0f92f511daef 100644 ---- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -@@ -57,6 +57,7 @@ public class CraftPersistentDataContainer implements PersistentDataContainer { - - @Override - public boolean has(NamespacedKey key) { -+ Preconditions.checkArgument(key != null, "The provided key for the custom value was null"); // Paper - return this.customDataTags.get(key.toString()) != null; - } - diff --git a/patches/server/0644-Multiple-Entries-with-Scoreboards.patch b/patches/server/0644-Multiple-Entries-with-Scoreboards.patch new file mode 100644 index 0000000000..558cc93da5 --- /dev/null +++ b/patches/server/0644-Multiple-Entries-with-Scoreboards.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Tue, 21 Sep 2021 18:17:33 -0500 +Subject: [PATCH] Multiple Entries with Scoreboards + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java +index 1d0c473442b5c72245c356054440323e3c5d4711..f8fe125f12a6a00899d1d6acfa448be882b81557 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java +@@ -58,6 +58,11 @@ public class ClientboundSetPlayerTeamPacket implements Packet players, ClientboundSetPlayerTeamPacket.Action operation) { ++ return new ClientboundSetPlayerTeamPacket(team.getName(), operation == ClientboundSetPlayerTeamPacket.Action.ADD ? 3 : 4, Optional.empty(), players); ++ } ++ // Paper end - Multiple Entries with Scoreboards + private ClientboundSetPlayerTeamPacket(RegistryFriendlyByteBuf buf) { + this.name = buf.readUtf(); + this.method = buf.readByte(); +diff --git a/src/main/java/net/minecraft/server/ServerScoreboard.java b/src/main/java/net/minecraft/server/ServerScoreboard.java +index f1e72463ca11658390f662efbaf3e551c05fe799..8fd4d8ffcc9e1a0fcf83730d26c3bb9bef0f73f2 100644 +--- a/src/main/java/net/minecraft/server/ServerScoreboard.java ++++ b/src/main/java/net/minecraft/server/ServerScoreboard.java +@@ -106,6 +106,25 @@ public class ServerScoreboard extends Scoreboard { + } + } + ++ // Paper start - Multiple Entries with Scoreboards ++ public boolean addPlayersToTeam(java.util.Collection players, PlayerTeam team) { ++ boolean anyAdded = false; ++ for (String playerName : players) { ++ if (super.addPlayerToTeam(playerName, team)) { ++ anyAdded = true; ++ } ++ } ++ ++ if (anyAdded) { ++ this.broadcastAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.ADD)); ++ this.setDirty(); ++ return true; ++ } else { ++ return false; ++ } ++ } ++ // Paper end - Multiple Entries with Scoreboards ++ + @Override + public void removePlayerFromTeam(String scoreHolderName, PlayerTeam team) { + super.removePlayerFromTeam(scoreHolderName, team); +@@ -113,6 +132,17 @@ public class ServerScoreboard extends Scoreboard { + this.setDirty(); + } + ++ // Paper start - Multiple Entries with Scoreboards ++ public void removePlayersFromTeam(java.util.Collection players, PlayerTeam team) { ++ for (String playerName : players) { ++ super.removePlayerFromTeam(playerName, team); ++ } ++ ++ this.broadcastAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.REMOVE)); ++ this.setDirty(); ++ } ++ // Paper end - Multiple Entries with Scoreboards ++ + @Override + public void onObjectiveAdded(Objective objective) { + super.onObjectiveAdded(objective); +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java +index 27219bf2f16aed64c78623d44c3cc84aa9f47065..2b335c750ce5f9ccc2651a8701497ca9b8f46704 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java +@@ -229,6 +229,21 @@ final class CraftTeam extends CraftScoreboardComponent implements Team { + scoreboard.board.addPlayerToTeam(entry, this.team); + } + ++ // Paper start - Multiple Entries with Scoreboards ++ @Override ++ public void addEntities(java.util.Collection entities) throws IllegalStateException, IllegalArgumentException { ++ this.addEntries(entities.stream().map(entity -> ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()).toList()); ++ } ++ ++ @Override ++ public void addEntries(java.util.Collection entries) throws IllegalStateException, IllegalArgumentException { ++ Preconditions.checkArgument(entries != null, "Entries cannot be null"); ++ CraftScoreboard scoreboard = this.checkState(); ++ ++ ((net.minecraft.server.ServerScoreboard) scoreboard.board).addPlayersToTeam(entries, this.team); ++ } ++ // Paper end - Multiple Entries with Scoreboards ++ + @Override + public boolean removePlayer(OfflinePlayer player) { + Preconditions.checkArgument(player != null, "OfflinePlayer cannot be null"); +@@ -248,6 +263,28 @@ final class CraftTeam extends CraftScoreboardComponent implements Team { + return true; + } + ++ // Paper start - Multiple Entries with Scoreboards ++ @Override ++ public boolean removeEntities(java.util.Collection entities) throws IllegalStateException, IllegalArgumentException { ++ return this.removeEntries(entities.stream().map(entity -> ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()).toList()); ++ } ++ ++ @Override ++ public boolean removeEntries(java.util.Collection entries) throws IllegalStateException, IllegalArgumentException { ++ Preconditions.checkArgument(entries != null, "Entry cannot be null"); ++ CraftScoreboard scoreboard = this.checkState(); ++ ++ for (String entry : entries) { ++ if (this.team.getPlayers().contains(entry)) { ++ ((net.minecraft.server.ServerScoreboard) scoreboard.board).removePlayersFromTeam(entries, this.team); ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ // Paper end - Multiple Entries with Scoreboards ++ + @Override + public boolean hasPlayer(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException { + Preconditions.checkArgument(player != null, "OfflinePlayer cannot be null"); diff --git a/patches/server/0645-Multiple-Entries-with-Scoreboards.patch b/patches/server/0645-Multiple-Entries-with-Scoreboards.patch deleted file mode 100644 index 558cc93da5..0000000000 --- a/patches/server/0645-Multiple-Entries-with-Scoreboards.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cryptite -Date: Tue, 21 Sep 2021 18:17:33 -0500 -Subject: [PATCH] Multiple Entries with Scoreboards - - -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java -index 1d0c473442b5c72245c356054440323e3c5d4711..f8fe125f12a6a00899d1d6acfa448be882b81557 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java -@@ -58,6 +58,11 @@ public class ClientboundSetPlayerTeamPacket implements Packet players, ClientboundSetPlayerTeamPacket.Action operation) { -+ return new ClientboundSetPlayerTeamPacket(team.getName(), operation == ClientboundSetPlayerTeamPacket.Action.ADD ? 3 : 4, Optional.empty(), players); -+ } -+ // Paper end - Multiple Entries with Scoreboards - private ClientboundSetPlayerTeamPacket(RegistryFriendlyByteBuf buf) { - this.name = buf.readUtf(); - this.method = buf.readByte(); -diff --git a/src/main/java/net/minecraft/server/ServerScoreboard.java b/src/main/java/net/minecraft/server/ServerScoreboard.java -index f1e72463ca11658390f662efbaf3e551c05fe799..8fd4d8ffcc9e1a0fcf83730d26c3bb9bef0f73f2 100644 ---- a/src/main/java/net/minecraft/server/ServerScoreboard.java -+++ b/src/main/java/net/minecraft/server/ServerScoreboard.java -@@ -106,6 +106,25 @@ public class ServerScoreboard extends Scoreboard { - } - } - -+ // Paper start - Multiple Entries with Scoreboards -+ public boolean addPlayersToTeam(java.util.Collection players, PlayerTeam team) { -+ boolean anyAdded = false; -+ for (String playerName : players) { -+ if (super.addPlayerToTeam(playerName, team)) { -+ anyAdded = true; -+ } -+ } -+ -+ if (anyAdded) { -+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.ADD)); -+ this.setDirty(); -+ return true; -+ } else { -+ return false; -+ } -+ } -+ // Paper end - Multiple Entries with Scoreboards -+ - @Override - public void removePlayerFromTeam(String scoreHolderName, PlayerTeam team) { - super.removePlayerFromTeam(scoreHolderName, team); -@@ -113,6 +132,17 @@ public class ServerScoreboard extends Scoreboard { - this.setDirty(); - } - -+ // Paper start - Multiple Entries with Scoreboards -+ public void removePlayersFromTeam(java.util.Collection players, PlayerTeam team) { -+ for (String playerName : players) { -+ super.removePlayerFromTeam(playerName, team); -+ } -+ -+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.REMOVE)); -+ this.setDirty(); -+ } -+ // Paper end - Multiple Entries with Scoreboards -+ - @Override - public void onObjectiveAdded(Objective objective) { - super.onObjectiveAdded(objective); -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java -index 27219bf2f16aed64c78623d44c3cc84aa9f47065..2b335c750ce5f9ccc2651a8701497ca9b8f46704 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java -@@ -229,6 +229,21 @@ final class CraftTeam extends CraftScoreboardComponent implements Team { - scoreboard.board.addPlayerToTeam(entry, this.team); - } - -+ // Paper start - Multiple Entries with Scoreboards -+ @Override -+ public void addEntities(java.util.Collection entities) throws IllegalStateException, IllegalArgumentException { -+ this.addEntries(entities.stream().map(entity -> ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()).toList()); -+ } -+ -+ @Override -+ public void addEntries(java.util.Collection entries) throws IllegalStateException, IllegalArgumentException { -+ Preconditions.checkArgument(entries != null, "Entries cannot be null"); -+ CraftScoreboard scoreboard = this.checkState(); -+ -+ ((net.minecraft.server.ServerScoreboard) scoreboard.board).addPlayersToTeam(entries, this.team); -+ } -+ // Paper end - Multiple Entries with Scoreboards -+ - @Override - public boolean removePlayer(OfflinePlayer player) { - Preconditions.checkArgument(player != null, "OfflinePlayer cannot be null"); -@@ -248,6 +263,28 @@ final class CraftTeam extends CraftScoreboardComponent implements Team { - return true; - } - -+ // Paper start - Multiple Entries with Scoreboards -+ @Override -+ public boolean removeEntities(java.util.Collection entities) throws IllegalStateException, IllegalArgumentException { -+ return this.removeEntries(entities.stream().map(entity -> ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()).toList()); -+ } -+ -+ @Override -+ public boolean removeEntries(java.util.Collection entries) throws IllegalStateException, IllegalArgumentException { -+ Preconditions.checkArgument(entries != null, "Entry cannot be null"); -+ CraftScoreboard scoreboard = this.checkState(); -+ -+ for (String entry : entries) { -+ if (this.team.getPlayers().contains(entry)) { -+ ((net.minecraft.server.ServerScoreboard) scoreboard.board).removePlayersFromTeam(entries, this.team); -+ return true; -+ } -+ } -+ -+ return false; -+ } -+ // Paper end - Multiple Entries with Scoreboards -+ - @Override - public boolean hasPlayer(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException { - Preconditions.checkArgument(player != null, "OfflinePlayer cannot be null"); diff --git a/patches/server/0645-Reset-placed-block-on-exception.patch b/patches/server/0645-Reset-placed-block-on-exception.patch new file mode 100644 index 0000000000..327d98e291 --- /dev/null +++ b/patches/server/0645-Reset-placed-block-on-exception.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Fri, 7 Jan 2022 11:45:15 +0100 +Subject: [PATCH] Reset placed block on exception + + +diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java +index 407f5db0a4b3884440bc49bf4f00d9c035899e86..44cc12a3338b5f0448c88192c8674cd36531db34 100644 +--- a/src/main/java/net/minecraft/world/item/BlockItem.java ++++ b/src/main/java/net/minecraft/world/item/BlockItem.java +@@ -71,6 +71,7 @@ public class BlockItem extends Item { + if (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem) { + blockstate = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos()); + } ++ final org.bukkit.block.BlockState oldBlockstate = blockstate != null ? blockstate : org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos()); // Paper - Reset placed block on exception + // CraftBukkit end + + if (iblockdata == null) { +@@ -86,8 +87,20 @@ public class BlockItem extends Item { + + if (iblockdata1.is(iblockdata.getBlock())) { + iblockdata1 = this.updateBlockStateFromTag(blockposition, world, itemstack, iblockdata1); ++ // Paper start - Reset placed block on exception ++ try { + this.updateCustomBlockEntityTag(blockposition, world, entityhuman, itemstack, iblockdata1); + BlockItem.updateBlockEntityComponents(world, blockposition, itemstack); ++ } catch (Exception e) { ++ oldBlockstate.update(true, false); ++ if (entityhuman instanceof ServerPlayer player) { ++ org.apache.logging.log4j.LogManager.getLogger().error("Player {} tried placing invalid block", player.getScoreboardName(), e); ++ player.getBukkitEntity().kickPlayer("Packet processing error"); ++ return InteractionResult.FAIL; ++ } ++ throw e; // Rethrow exception if not placed by a player ++ } ++ // Paper end - Reset placed block on exception + iblockdata1.getBlock().setPlacedBy(world, blockposition, iblockdata1, entityhuman, itemstack); + // CraftBukkit start + if (blockstate != null) { diff --git a/patches/server/0646-Add-configurable-height-for-slime-spawn.patch b/patches/server/0646-Add-configurable-height-for-slime-spawn.patch new file mode 100644 index 0000000000..dfc8ecb349 --- /dev/null +++ b/patches/server/0646-Add-configurable-height-for-slime-spawn.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Doc +Date: Mon, 2 Aug 2021 11:24:39 -0400 +Subject: [PATCH] Add configurable height for slime spawn + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java +index 129f0cbc0469cb2804db6088b53347d88d91f4eb..72346a7e5269c91e3143933ac37e65ad9639b791 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java +@@ -340,7 +340,11 @@ public class Slime extends Mob implements Enemy { + return checkMobSpawnRules(type, world, spawnReason, pos, random); + } + +- if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > 50 && pos.getY() < 70 && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { ++ // Paper start - Replace rules for Height in Swamp Biome ++ final double maxHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.maximum; ++ final double minHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.minimum; ++ if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > minHeightSwamp && pos.getY() < maxHeightSwamp && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { ++ // Paper end - Replace rules for Height in Swamp Biome + return checkMobSpawnRules(type, world, spawnReason, pos, random); + } + +@@ -351,7 +355,10 @@ public class Slime extends Mob implements Enemy { + ChunkPos chunkcoordintpair = new ChunkPos(pos); + boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper + +- if (random.nextInt(10) == 0 && flag && pos.getY() < 40) { ++ // Paper start - Replace rules for Height in Slime Chunks ++ final double maxHeightSlimeChunk = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum; ++ if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) { ++ // Paper end - Replace rules for Height in Slime Chunks + return checkMobSpawnRules(type, world, spawnReason, pos, random); + } + } diff --git a/patches/server/0646-Reset-placed-block-on-exception.patch b/patches/server/0646-Reset-placed-block-on-exception.patch deleted file mode 100644 index 327d98e291..0000000000 --- a/patches/server/0646-Reset-placed-block-on-exception.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Fri, 7 Jan 2022 11:45:15 +0100 -Subject: [PATCH] Reset placed block on exception - - -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 407f5db0a4b3884440bc49bf4f00d9c035899e86..44cc12a3338b5f0448c88192c8674cd36531db34 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -71,6 +71,7 @@ public class BlockItem extends Item { - if (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem) { - blockstate = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos()); - } -+ final org.bukkit.block.BlockState oldBlockstate = blockstate != null ? blockstate : org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos()); // Paper - Reset placed block on exception - // CraftBukkit end - - if (iblockdata == null) { -@@ -86,8 +87,20 @@ public class BlockItem extends Item { - - if (iblockdata1.is(iblockdata.getBlock())) { - iblockdata1 = this.updateBlockStateFromTag(blockposition, world, itemstack, iblockdata1); -+ // Paper start - Reset placed block on exception -+ try { - this.updateCustomBlockEntityTag(blockposition, world, entityhuman, itemstack, iblockdata1); - BlockItem.updateBlockEntityComponents(world, blockposition, itemstack); -+ } catch (Exception e) { -+ oldBlockstate.update(true, false); -+ if (entityhuman instanceof ServerPlayer player) { -+ org.apache.logging.log4j.LogManager.getLogger().error("Player {} tried placing invalid block", player.getScoreboardName(), e); -+ player.getBukkitEntity().kickPlayer("Packet processing error"); -+ return InteractionResult.FAIL; -+ } -+ throw e; // Rethrow exception if not placed by a player -+ } -+ // Paper end - Reset placed block on exception - iblockdata1.getBlock().setPlacedBy(world, blockposition, iblockdata1, entityhuman, itemstack); - // CraftBukkit start - if (blockstate != null) { diff --git a/patches/server/0647-Add-configurable-height-for-slime-spawn.patch b/patches/server/0647-Add-configurable-height-for-slime-spawn.patch deleted file mode 100644 index dfc8ecb349..0000000000 --- a/patches/server/0647-Add-configurable-height-for-slime-spawn.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Doc -Date: Mon, 2 Aug 2021 11:24:39 -0400 -Subject: [PATCH] Add configurable height for slime spawn - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java -index 129f0cbc0469cb2804db6088b53347d88d91f4eb..72346a7e5269c91e3143933ac37e65ad9639b791 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Slime.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java -@@ -340,7 +340,11 @@ public class Slime extends Mob implements Enemy { - return checkMobSpawnRules(type, world, spawnReason, pos, random); - } - -- if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > 50 && pos.getY() < 70 && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { -+ // Paper start - Replace rules for Height in Swamp Biome -+ final double maxHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.maximum; -+ final double minHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.minimum; -+ if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > minHeightSwamp && pos.getY() < maxHeightSwamp && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { -+ // Paper end - Replace rules for Height in Swamp Biome - return checkMobSpawnRules(type, world, spawnReason, pos, random); - } - -@@ -351,7 +355,10 @@ public class Slime extends Mob implements Enemy { - ChunkPos chunkcoordintpair = new ChunkPos(pos); - boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper - -- if (random.nextInt(10) == 0 && flag && pos.getY() < 40) { -+ // Paper start - Replace rules for Height in Slime Chunks -+ final double maxHeightSlimeChunk = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum; -+ if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) { -+ // Paper end - Replace rules for Height in Slime Chunks - return checkMobSpawnRules(type, world, spawnReason, pos, random); - } - } diff --git a/patches/server/0647-Fix-xp-reward-for-baby-zombies.patch b/patches/server/0647-Fix-xp-reward-for-baby-zombies.patch new file mode 100644 index 0000000000..3ec320760f --- /dev/null +++ b/patches/server/0647-Fix-xp-reward-for-baby-zombies.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 16 Jan 2022 10:34:02 -0800 +Subject: [PATCH] Fix xp reward for baby zombies + +The field that tracks the xpReward was not +getting reset if the death was cancelled +so this resets it after each call to +Zombie#getExperienceReward + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +index a835ec6e063dd247a008da84446f8647f38d89d4..94b3ba2688676e92d9d093b63d92cab39d5d2f02 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +@@ -174,11 +174,16 @@ public class Zombie extends Monster { + + @Override + protected int getBaseExperienceReward(ServerLevel world) { ++ final int previousReward = this.xpReward; // Paper - store previous value to reset after calculating XP reward + if (this.isBaby()) { + this.xpReward = (int) ((double) this.xpReward * 2.5D); + } + +- return super.getBaseExperienceReward(world); ++ // Paper start - store previous value to reset after calculating XP reward ++ int reward = super.getBaseExperienceReward(world); ++ this.xpReward = previousReward; ++ return reward; ++ // Paper end - store previous value to reset after calculating XP reward + } + + @Override diff --git a/patches/server/0648-Fix-xp-reward-for-baby-zombies.patch b/patches/server/0648-Fix-xp-reward-for-baby-zombies.patch deleted file mode 100644 index 3ec320760f..0000000000 --- a/patches/server/0648-Fix-xp-reward-for-baby-zombies.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 16 Jan 2022 10:34:02 -0800 -Subject: [PATCH] Fix xp reward for baby zombies - -The field that tracks the xpReward was not -getting reset if the death was cancelled -so this resets it after each call to -Zombie#getExperienceReward - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index a835ec6e063dd247a008da84446f8647f38d89d4..94b3ba2688676e92d9d093b63d92cab39d5d2f02 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -174,11 +174,16 @@ public class Zombie extends Monster { - - @Override - protected int getBaseExperienceReward(ServerLevel world) { -+ final int previousReward = this.xpReward; // Paper - store previous value to reset after calculating XP reward - if (this.isBaby()) { - this.xpReward = (int) ((double) this.xpReward * 2.5D); - } - -- return super.getBaseExperienceReward(world); -+ // Paper start - store previous value to reset after calculating XP reward -+ int reward = super.getBaseExperienceReward(world); -+ this.xpReward = previousReward; -+ return reward; -+ // Paper end - store previous value to reset after calculating XP reward - } - - @Override diff --git a/patches/server/0648-Multi-Block-Change-API-Implementation.patch b/patches/server/0648-Multi-Block-Change-API-Implementation.patch new file mode 100644 index 0000000000..9edd052d01 --- /dev/null +++ b/patches/server/0648-Multi-Block-Change-API-Implementation.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brody Beckwith +Date: Fri, 14 Jan 2022 00:41:11 -0500 +Subject: [PATCH] Multi Block Change API Implementation + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java +index 926ff9be3d9e3f5d620e4c7ccb22b9f64865ff8c..1a37654aff9a9c86c9f7af10a1cf721371f0c5ec 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java +@@ -62,6 +62,14 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet blockChanges) { ++ this.sectionPos = sectionPos; ++ this.positions = blockChanges.keySet().toShortArray(); ++ this.states = blockChanges.values().toArray(new BlockState[0]); ++ } ++ // Paper end - Multi Block Change API ++ + private void write(FriendlyByteBuf buf) { + buf.writeLong(this.sectionPos.asLong()); + buf.writeVarInt(this.positions.length); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index ca13d317a5e1c7b7ccda3fdec63e2146562649f6..fe0c355f8203c9bfa30d2ec48392a5a1a3d616ae 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -947,6 +947,32 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + this.getHandle().connection.send(packet); + } + ++ // Paper start ++ @Override ++ public void sendMultiBlockChange(final Map blockChanges) { ++ if (this.getHandle().connection == null) return; ++ ++ Map> sectionMap = new HashMap<>(); ++ ++ for (Map.Entry entry : blockChanges.entrySet()) { ++ BlockData blockData = entry.getValue(); ++ BlockPos blockPos = io.papermc.paper.util.MCUtil.toBlockPos(entry.getKey()); ++ SectionPos sectionPos = SectionPos.of(blockPos); ++ ++ it.unimi.dsi.fastutil.shorts.Short2ObjectMap sectionData = sectionMap.computeIfAbsent(sectionPos, key -> new it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap<>()); ++ sectionData.put(SectionPos.sectionRelativePos(blockPos), ((CraftBlockData) blockData).getState()); ++ } ++ ++ for (Map.Entry> entry : sectionMap.entrySet()) { ++ SectionPos sectionPos = entry.getKey(); ++ it.unimi.dsi.fastutil.shorts.Short2ObjectMap blockData = entry.getValue(); ++ ++ net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket packet = new net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket(sectionPos, blockData); ++ this.getHandle().connection.send(packet); ++ } ++ } ++ // Paper end ++ + @Override + public void sendBlockChanges(Collection blocks) { + Preconditions.checkArgument(blocks != null, "blocks must not be null"); diff --git a/patches/server/0649-Fix-NotePlayEvent.patch b/patches/server/0649-Fix-NotePlayEvent.patch new file mode 100644 index 0000000000..cdffcd6f0f --- /dev/null +++ b/patches/server/0649-Fix-NotePlayEvent.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kieran Wallbanks +Date: Mon, 21 Jun 2021 14:23:50 +0100 +Subject: [PATCH] Fix NotePlayEvent + +== AT == +public org.bukkit.craftbukkit.block.data.CraftBlockData toNMS(Ljava/lang/Enum;Ljava/lang/Class;)Ljava/lang/Enum; + +diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java +index 57e13269367a82ec39c2298b20d7595f61326f47..71fd7a467a4cb89cad8d2541366fd4add9115e04 100644 +--- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java +@@ -96,11 +96,12 @@ public class NoteBlock extends Block { + private void playNote(@Nullable Entity entity, BlockState state, Level world, BlockPos pos) { + if (((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) { + // CraftBukkit start +- org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE)); +- if (event.isCancelled()) { +- return; +- } ++ // org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE)); ++ // if (event.isCancelled()) { ++ // return; ++ // } + // CraftBukkit end ++ // Paper - move NotePlayEvent call to fix instrument/note changes; TODO any way to cancel the game event? + world.blockEvent(pos, this, 0, 0); + world.gameEvent(entity, (Holder) GameEvent.NOTE_BLOCK_PLAY, pos); + } +@@ -139,10 +140,14 @@ public class NoteBlock extends Block { + @Override + protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) { + NoteBlockInstrument blockpropertyinstrument = (NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT); ++ // Paper start - move NotePlayEvent call to fix instrument/note changes ++ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, blockpropertyinstrument, state.getValue(NOTE)); ++ if (event.isCancelled()) return false; ++ // Paper end - move NotePlayEvent call to fix instrument/note changes + float f; + + if (blockpropertyinstrument.isTunable()) { +- int k = (Integer) state.getValue(NoteBlock.NOTE); ++ int k = event.getNote().getId(); // Paper - move NotePlayEvent call to fix instrument/note changes + + f = NoteBlock.getPitchFromNote(k); + world.addParticle(ParticleTypes.NOTE, (double) pos.getX() + 0.5D, (double) pos.getY() + 1.2D, (double) pos.getZ() + 0.5D, (double) k / 24.0D, 0.0D, 0.0D); +@@ -161,7 +166,7 @@ public class NoteBlock extends Block { + + holder = Holder.direct(SoundEvent.createVariableRangeEvent(minecraftkey)); + } else { +- holder = blockpropertyinstrument.getSoundEvent(); ++ holder = org.bukkit.craftbukkit.block.data.CraftBlockData.toNMS(event.getInstrument(), NoteBlockInstrument.class).getSoundEvent(); // Paper - move NotePlayEvent call to fix instrument/note changes + } + + world.playSeededSound((Player) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, holder, SoundSource.RECORDS, 3.0F, f, world.random.nextLong()); diff --git a/patches/server/0649-Multi-Block-Change-API-Implementation.patch b/patches/server/0649-Multi-Block-Change-API-Implementation.patch deleted file mode 100644 index 9edd052d01..0000000000 --- a/patches/server/0649-Multi-Block-Change-API-Implementation.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brody Beckwith -Date: Fri, 14 Jan 2022 00:41:11 -0500 -Subject: [PATCH] Multi Block Change API Implementation - - -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java -index 926ff9be3d9e3f5d620e4c7ccb22b9f64865ff8c..1a37654aff9a9c86c9f7af10a1cf721371f0c5ec 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java -@@ -62,6 +62,14 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet blockChanges) { -+ this.sectionPos = sectionPos; -+ this.positions = blockChanges.keySet().toShortArray(); -+ this.states = blockChanges.values().toArray(new BlockState[0]); -+ } -+ // Paper end - Multi Block Change API -+ - private void write(FriendlyByteBuf buf) { - buf.writeLong(this.sectionPos.asLong()); - buf.writeVarInt(this.positions.length); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index ca13d317a5e1c7b7ccda3fdec63e2146562649f6..fe0c355f8203c9bfa30d2ec48392a5a1a3d616ae 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -947,6 +947,32 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - this.getHandle().connection.send(packet); - } - -+ // Paper start -+ @Override -+ public void sendMultiBlockChange(final Map blockChanges) { -+ if (this.getHandle().connection == null) return; -+ -+ Map> sectionMap = new HashMap<>(); -+ -+ for (Map.Entry entry : blockChanges.entrySet()) { -+ BlockData blockData = entry.getValue(); -+ BlockPos blockPos = io.papermc.paper.util.MCUtil.toBlockPos(entry.getKey()); -+ SectionPos sectionPos = SectionPos.of(blockPos); -+ -+ it.unimi.dsi.fastutil.shorts.Short2ObjectMap sectionData = sectionMap.computeIfAbsent(sectionPos, key -> new it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap<>()); -+ sectionData.put(SectionPos.sectionRelativePos(blockPos), ((CraftBlockData) blockData).getState()); -+ } -+ -+ for (Map.Entry> entry : sectionMap.entrySet()) { -+ SectionPos sectionPos = entry.getKey(); -+ it.unimi.dsi.fastutil.shorts.Short2ObjectMap blockData = entry.getValue(); -+ -+ net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket packet = new net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket(sectionPos, blockData); -+ this.getHandle().connection.send(packet); -+ } -+ } -+ // Paper end -+ - @Override - public void sendBlockChanges(Collection blocks) { - Preconditions.checkArgument(blocks != null, "blocks must not be null"); diff --git a/patches/server/0650-Fix-NotePlayEvent.patch b/patches/server/0650-Fix-NotePlayEvent.patch deleted file mode 100644 index cdffcd6f0f..0000000000 --- a/patches/server/0650-Fix-NotePlayEvent.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Kieran Wallbanks -Date: Mon, 21 Jun 2021 14:23:50 +0100 -Subject: [PATCH] Fix NotePlayEvent - -== AT == -public org.bukkit.craftbukkit.block.data.CraftBlockData toNMS(Ljava/lang/Enum;Ljava/lang/Class;)Ljava/lang/Enum; - -diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -index 57e13269367a82ec39c2298b20d7595f61326f47..71fd7a467a4cb89cad8d2541366fd4add9115e04 100644 ---- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -@@ -96,11 +96,12 @@ public class NoteBlock extends Block { - private void playNote(@Nullable Entity entity, BlockState state, Level world, BlockPos pos) { - if (((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) { - // CraftBukkit start -- org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE)); -- if (event.isCancelled()) { -- return; -- } -+ // org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE)); -+ // if (event.isCancelled()) { -+ // return; -+ // } - // CraftBukkit end -+ // Paper - move NotePlayEvent call to fix instrument/note changes; TODO any way to cancel the game event? - world.blockEvent(pos, this, 0, 0); - world.gameEvent(entity, (Holder) GameEvent.NOTE_BLOCK_PLAY, pos); - } -@@ -139,10 +140,14 @@ public class NoteBlock extends Block { - @Override - protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) { - NoteBlockInstrument blockpropertyinstrument = (NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT); -+ // Paper start - move NotePlayEvent call to fix instrument/note changes -+ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, blockpropertyinstrument, state.getValue(NOTE)); -+ if (event.isCancelled()) return false; -+ // Paper end - move NotePlayEvent call to fix instrument/note changes - float f; - - if (blockpropertyinstrument.isTunable()) { -- int k = (Integer) state.getValue(NoteBlock.NOTE); -+ int k = event.getNote().getId(); // Paper - move NotePlayEvent call to fix instrument/note changes - - f = NoteBlock.getPitchFromNote(k); - world.addParticle(ParticleTypes.NOTE, (double) pos.getX() + 0.5D, (double) pos.getY() + 1.2D, (double) pos.getZ() + 0.5D, (double) k / 24.0D, 0.0D, 0.0D); -@@ -161,7 +166,7 @@ public class NoteBlock extends Block { - - holder = Holder.direct(SoundEvent.createVariableRangeEvent(minecraftkey)); - } else { -- holder = blockpropertyinstrument.getSoundEvent(); -+ holder = org.bukkit.craftbukkit.block.data.CraftBlockData.toNMS(event.getInstrument(), NoteBlockInstrument.class).getSoundEvent(); // Paper - move NotePlayEvent call to fix instrument/note changes - } - - world.playSeededSound((Player) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, holder, SoundSource.RECORDS, 3.0F, f, world.random.nextLong()); diff --git a/patches/server/0650-Freeze-Tick-Lock-API.patch b/patches/server/0650-Freeze-Tick-Lock-API.patch new file mode 100644 index 0000000000..f658b3b299 --- /dev/null +++ b/patches/server/0650-Freeze-Tick-Lock-API.patch @@ -0,0 +1,82 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 26 Dec 2021 20:27:43 -0500 +Subject: [PATCH] Freeze Tick Lock API + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 3df8cfccba9bc4420b37dcbdfc4a12c720b51205..4f9ebf7a577223d85ceaad0babd2d0b4f492b6df 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -414,6 +414,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + private org.bukkit.util.Vector origin; + @javax.annotation.Nullable + private UUID originWorld; ++ public boolean freezeLocked = false; // Paper - Freeze Tick Lock API + + public void setOrigin(@javax.annotation.Nonnull Location location) { + this.origin = location.toVector(); +@@ -759,7 +760,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.setRemainingFireTicks(this.remainingFireTicks - 1); + } + +- if (this.getTicksFrozen() > 0) { ++ if (this.getTicksFrozen() > 0 && !freezeLocked) { // Paper - Freeze Tick Lock API + this.setTicksFrozen(0); + this.level().levelEvent((Player) null, 1009, this.blockPosition, 1); + } +@@ -2428,6 +2429,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (fromNetherPortal) { + nbttagcompound.putBoolean("Paper.FromNetherPortal", true); + } ++ if (freezeLocked) { ++ nbttagcompound.putBoolean("Paper.FreezeLock", true); ++ } + // Paper end + return nbttagcompound; + } catch (Throwable throwable) { +@@ -2573,6 +2577,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (spawnReason == null) { + spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; + } ++ if (nbt.contains("Paper.FreezeLock")) { ++ freezeLocked = nbt.getBoolean("Paper.FreezeLock"); ++ } + // Paper end + + } catch (Throwable throwable) { +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 8e0805bf6d330717f7555fbdb28d416295f8495a..8b454382f59ee36ec6f45ca8445b3f1a956ff668 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3609,7 +3609,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.calculateEntityAnimation(this instanceof FlyingAnimal); + gameprofilerfiller.pop(); + gameprofilerfiller.push("freezing"); +- if (!this.level().isClientSide && !this.isDeadOrDying()) { ++ if (!this.level().isClientSide && !this.isDeadOrDying() && !this.freezeLocked) { // Paper - Freeze Tick Lock API + int i = this.getTicksFrozen(); + + if (this.isInPowderSnow && this.canFreeze()) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 9693656418210957000add9b6670c4bee67f8462..4e6afa243d6108cb946a8a7cf96c4036a3c2ac0c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -324,6 +324,17 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return this.getHandle().isFullyFrozen(); + } + ++ // Paper start - Freeze Tick Lock API ++ @Override ++ public boolean isFreezeTickingLocked() { ++ return this.entity.freezeLocked; ++ } ++ ++ @Override ++ public void lockFreezeTicks(boolean locked) { ++ this.entity.freezeLocked = locked; ++ } ++ // Paper end - Freeze Tick Lock API + @Override + public void remove() { + this.entity.pluginRemoved = true; diff --git a/patches/server/0651-Freeze-Tick-Lock-API.patch b/patches/server/0651-Freeze-Tick-Lock-API.patch deleted file mode 100644 index 0244ffe420..0000000000 --- a/patches/server/0651-Freeze-Tick-Lock-API.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 26 Dec 2021 20:27:43 -0500 -Subject: [PATCH] Freeze Tick Lock API - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 3df8cfccba9bc4420b37dcbdfc4a12c720b51205..4f9ebf7a577223d85ceaad0babd2d0b4f492b6df 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -414,6 +414,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - private org.bukkit.util.Vector origin; - @javax.annotation.Nullable - private UUID originWorld; -+ public boolean freezeLocked = false; // Paper - Freeze Tick Lock API - - public void setOrigin(@javax.annotation.Nonnull Location location) { - this.origin = location.toVector(); -@@ -759,7 +760,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.setRemainingFireTicks(this.remainingFireTicks - 1); - } - -- if (this.getTicksFrozen() > 0) { -+ if (this.getTicksFrozen() > 0 && !freezeLocked) { // Paper - Freeze Tick Lock API - this.setTicksFrozen(0); - this.level().levelEvent((Player) null, 1009, this.blockPosition, 1); - } -@@ -2428,6 +2429,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (fromNetherPortal) { - nbttagcompound.putBoolean("Paper.FromNetherPortal", true); - } -+ if (freezeLocked) { -+ nbttagcompound.putBoolean("Paper.FreezeLock", true); -+ } - // Paper end - return nbttagcompound; - } catch (Throwable throwable) { -@@ -2573,6 +2577,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (spawnReason == null) { - spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; - } -+ if (nbt.contains("Paper.FreezeLock")) { -+ freezeLocked = nbt.getBoolean("Paper.FreezeLock"); -+ } - // Paper end - - } catch (Throwable throwable) { -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 8c7ffa884f64a4263c9399953a7cfca6e35aab61..0aa7291b3c28c58767fed5f9f01e381b671b5d27 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3611,7 +3611,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.calculateEntityAnimation(this instanceof FlyingAnimal); - gameprofilerfiller.pop(); - gameprofilerfiller.push("freezing"); -- if (!this.level().isClientSide && !this.isDeadOrDying()) { -+ if (!this.level().isClientSide && !this.isDeadOrDying() && !this.freezeLocked) { // Paper - Freeze Tick Lock API - int i = this.getTicksFrozen(); - - if (this.isInPowderSnow && this.canFreeze()) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 9693656418210957000add9b6670c4bee67f8462..4e6afa243d6108cb946a8a7cf96c4036a3c2ac0c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -324,6 +324,17 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return this.getHandle().isFullyFrozen(); - } - -+ // Paper start - Freeze Tick Lock API -+ @Override -+ public boolean isFreezeTickingLocked() { -+ return this.entity.freezeLocked; -+ } -+ -+ @Override -+ public void lockFreezeTicks(boolean locked) { -+ this.entity.freezeLocked = locked; -+ } -+ // Paper end - Freeze Tick Lock API - @Override - public void remove() { - this.entity.pluginRemoved = true; diff --git a/patches/server/0651-More-PotionEffectType-API.patch b/patches/server/0651-More-PotionEffectType-API.patch new file mode 100644 index 0000000000..2773c98338 --- /dev/null +++ b/patches/server/0651-More-PotionEffectType-API.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 27 May 2021 21:58:24 -0700 +Subject: [PATCH] More PotionEffectType API + +== AT == +public net.minecraft.world.effect.MobEffect attributeModifiers +public net.minecraft.world.effect.MobEffect$AttributeTemplate + +diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java +index 21d4224c8993f521d6004d708ecbf71fa6d09306..6cf790c9fa23ea313423fdaeb7c181bf530828c6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java ++++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java +@@ -129,6 +129,48 @@ public class CraftPotionEffectType extends PotionEffectType implements Handleabl + return this.handle.getDescriptionId(); + } + ++ // Paper start ++ @Override ++ public java.util.Map getEffectAttributes() { ++ // re-create map each time because a nms MobEffect can have its attributes modified ++ final java.util.Map attributeMap = new java.util.HashMap<>(); ++ this.handle.attributeModifiers.forEach((attribute, attributeModifier) -> { ++ attributeMap.put( ++ org.bukkit.craftbukkit.attribute.CraftAttribute.minecraftHolderToBukkit(attribute), ++ // use zero as amplifier to get the base amount, as it is amount = base * (amplifier + 1) ++ org.bukkit.craftbukkit.attribute.CraftAttributeInstance.convert(attributeModifier.create(0)) ++ ); ++ }); ++ return java.util.Map.copyOf(attributeMap); ++ } ++ ++ @Override ++ public double getAttributeModifierAmount(org.bukkit.attribute.Attribute attribute, int effectAmplifier) { ++ com.google.common.base.Preconditions.checkArgument(effectAmplifier >= 0, "effectAmplifier must be greater than or equal to 0"); ++ Holder nmsAttribute = org.bukkit.craftbukkit.attribute.CraftAttribute.bukkitToMinecraftHolder(attribute); ++ com.google.common.base.Preconditions.checkArgument(this.handle.attributeModifiers.containsKey(nmsAttribute), attribute + " is not present on " + this.getKey()); ++ return this.handle.attributeModifiers.get(nmsAttribute).create(effectAmplifier).amount(); ++ } ++ ++ @Override ++ public PotionEffectType.Category getEffectCategory() { ++ return fromNMS(handle.getCategory()); ++ } ++ ++ @Override ++ public String translationKey() { ++ return this.handle.getDescriptionId(); ++ } ++ ++ public static PotionEffectType.Category fromNMS(net.minecraft.world.effect.MobEffectCategory mobEffectInfo) { ++ return switch (mobEffectInfo) { ++ case BENEFICIAL -> PotionEffectType.Category.BENEFICIAL; ++ case HARMFUL -> PotionEffectType.Category.HARMFUL; ++ case NEUTRAL -> PotionEffectType.Category.NEUTRAL; ++ }; ++ } ++ // Paper end ++ + @Override + public boolean equals(Object other) { + if (this == other) { +diff --git a/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java b/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a57e8fdc35efc7e0353d4f36c91578390ee4572e +--- /dev/null ++++ b/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.effects; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import net.minecraft.world.effect.MobEffectCategory; ++import org.bukkit.craftbukkit.potion.CraftPotionEffectType; ++import org.bukkit.potion.PotionEffectType; ++import org.bukkit.support.environment.AllFeatures; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++import static org.junit.jupiter.api.Assertions.assertNotNull; ++ ++@AllFeatures ++public class EffectCategoryTest { ++ ++ @Test ++ public void testEffectCategoriesExist() { ++ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) { ++ assertNotNull(CraftPotionEffectType.fromNMS(mobEffectInfo), mobEffectInfo + " is missing a bukkit equivalent"); ++ } ++ } ++ ++ @Test ++ public void testCategoryHasEquivalentColors() { ++ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) { ++ PotionEffectType.Category bukkitEffectCategory = CraftPotionEffectType.fromNMS(mobEffectInfo); ++ assertEquals(bukkitEffectCategory.getColor(), PaperAdventure.asAdventure(mobEffectInfo.getTooltipFormatting()), mobEffectInfo.getTooltipFormatting().name() + " doesn't equal " + bukkitEffectCategory.getColor()); ++ } ++ } ++} diff --git a/patches/server/0652-More-PotionEffectType-API.patch b/patches/server/0652-More-PotionEffectType-API.patch deleted file mode 100644 index 2773c98338..0000000000 --- a/patches/server/0652-More-PotionEffectType-API.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 27 May 2021 21:58:24 -0700 -Subject: [PATCH] More PotionEffectType API - -== AT == -public net.minecraft.world.effect.MobEffect attributeModifiers -public net.minecraft.world.effect.MobEffect$AttributeTemplate - -diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java -index 21d4224c8993f521d6004d708ecbf71fa6d09306..6cf790c9fa23ea313423fdaeb7c181bf530828c6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java -+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java -@@ -129,6 +129,48 @@ public class CraftPotionEffectType extends PotionEffectType implements Handleabl - return this.handle.getDescriptionId(); - } - -+ // Paper start -+ @Override -+ public java.util.Map getEffectAttributes() { -+ // re-create map each time because a nms MobEffect can have its attributes modified -+ final java.util.Map attributeMap = new java.util.HashMap<>(); -+ this.handle.attributeModifiers.forEach((attribute, attributeModifier) -> { -+ attributeMap.put( -+ org.bukkit.craftbukkit.attribute.CraftAttribute.minecraftHolderToBukkit(attribute), -+ // use zero as amplifier to get the base amount, as it is amount = base * (amplifier + 1) -+ org.bukkit.craftbukkit.attribute.CraftAttributeInstance.convert(attributeModifier.create(0)) -+ ); -+ }); -+ return java.util.Map.copyOf(attributeMap); -+ } -+ -+ @Override -+ public double getAttributeModifierAmount(org.bukkit.attribute.Attribute attribute, int effectAmplifier) { -+ com.google.common.base.Preconditions.checkArgument(effectAmplifier >= 0, "effectAmplifier must be greater than or equal to 0"); -+ Holder nmsAttribute = org.bukkit.craftbukkit.attribute.CraftAttribute.bukkitToMinecraftHolder(attribute); -+ com.google.common.base.Preconditions.checkArgument(this.handle.attributeModifiers.containsKey(nmsAttribute), attribute + " is not present on " + this.getKey()); -+ return this.handle.attributeModifiers.get(nmsAttribute).create(effectAmplifier).amount(); -+ } -+ -+ @Override -+ public PotionEffectType.Category getEffectCategory() { -+ return fromNMS(handle.getCategory()); -+ } -+ -+ @Override -+ public String translationKey() { -+ return this.handle.getDescriptionId(); -+ } -+ -+ public static PotionEffectType.Category fromNMS(net.minecraft.world.effect.MobEffectCategory mobEffectInfo) { -+ return switch (mobEffectInfo) { -+ case BENEFICIAL -> PotionEffectType.Category.BENEFICIAL; -+ case HARMFUL -> PotionEffectType.Category.HARMFUL; -+ case NEUTRAL -> PotionEffectType.Category.NEUTRAL; -+ }; -+ } -+ // Paper end -+ - @Override - public boolean equals(Object other) { - if (this == other) { -diff --git a/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java b/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a57e8fdc35efc7e0353d4f36c91578390ee4572e ---- /dev/null -+++ b/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java -@@ -0,0 +1,30 @@ -+package io.papermc.paper.effects; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import net.minecraft.world.effect.MobEffectCategory; -+import org.bukkit.craftbukkit.potion.CraftPotionEffectType; -+import org.bukkit.potion.PotionEffectType; -+import org.bukkit.support.environment.AllFeatures; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertEquals; -+import static org.junit.jupiter.api.Assertions.assertNotNull; -+ -+@AllFeatures -+public class EffectCategoryTest { -+ -+ @Test -+ public void testEffectCategoriesExist() { -+ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) { -+ assertNotNull(CraftPotionEffectType.fromNMS(mobEffectInfo), mobEffectInfo + " is missing a bukkit equivalent"); -+ } -+ } -+ -+ @Test -+ public void testCategoryHasEquivalentColors() { -+ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) { -+ PotionEffectType.Category bukkitEffectCategory = CraftPotionEffectType.fromNMS(mobEffectInfo); -+ assertEquals(bukkitEffectCategory.getColor(), PaperAdventure.asAdventure(mobEffectInfo.getTooltipFormatting()), mobEffectInfo.getTooltipFormatting().name() + " doesn't equal " + bukkitEffectCategory.getColor()); -+ } -+ } -+} diff --git a/patches/server/0652-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch b/patches/server/0652-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch new file mode 100644 index 0000000000..027285c2b1 --- /dev/null +++ b/patches/server/0652-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Mon, 12 Jul 2021 12:28:29 +0100 +Subject: [PATCH] Use a CHM for StructureTemplate.Pallete cache + +fixes a CME due to this collection being shared across threads + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +index e7900e7e8263cae131dad2427fb2bfdadf5b8d14..b120949667ae0169a667b329b3cabbd79a0a5bda 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +@@ -889,7 +889,7 @@ public class StructureTemplate { + public static final class Palette { + + private final List blocks; +- private final Map> cache = Maps.newHashMap(); ++ private final Map> cache = Maps.newConcurrentMap(); // Paper - Fix CME due to this collection being shared across threads + @Nullable + private List cachedJigsaws; + diff --git a/patches/server/0653-API-for-creating-command-sender-which-forwards-feedb.patch b/patches/server/0653-API-for-creating-command-sender-which-forwards-feedb.patch new file mode 100644 index 0000000000..76a09348af --- /dev/null +++ b/patches/server/0653-API-for-creating-command-sender-which-forwards-feedb.patch @@ -0,0 +1,170 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 1 Feb 2022 15:51:55 -0700 +Subject: [PATCH] API for creating command sender which forwards feedback + + +diff --git a/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java b/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e3a5f1ec376319bdfda87fa27ae217bff3914292 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java +@@ -0,0 +1,111 @@ ++package io.papermc.paper.commands; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import java.util.UUID; ++import java.util.function.Consumer; ++import net.kyori.adventure.audience.MessageType; ++import net.kyori.adventure.identity.Identity; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; ++import net.minecraft.commands.CommandSource; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.phys.Vec2; ++import net.minecraft.world.phys.Vec3; ++import org.bukkit.command.CommandSender; ++import org.bukkit.craftbukkit.CraftServer; ++import org.bukkit.craftbukkit.command.ServerCommandSender; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public final class FeedbackForwardingSender extends ServerCommandSender { ++ private final Consumer feedback; ++ private final CraftServer server; ++ ++ public FeedbackForwardingSender(final Consumer feedback, final CraftServer server) { ++ super(((ServerCommandSender) server.getConsoleSender()).perm); ++ this.server = server; ++ this.feedback = feedback; ++ } ++ ++ @Override ++ public void sendMessage(final String message) { ++ this.sendMessage(LegacyComponentSerializer.legacySection().deserialize(message)); ++ } ++ ++ @Override ++ public void sendMessage(final String... messages) { ++ for (final String message : messages) { ++ this.sendMessage(message); ++ } ++ } ++ ++ @Override ++ public void sendMessage(final Identity identity, final Component message, final MessageType type) { ++ this.feedback.accept(message); ++ } ++ ++ @Override ++ public String getName() { ++ return "FeedbackForwardingSender"; ++ } ++ ++ @Override ++ public Component name() { ++ return Component.text(this.getName()); ++ } ++ ++ @Override ++ public boolean isOp() { ++ return true; ++ } ++ ++ @Override ++ public void setOp(final boolean value) { ++ throw new UnsupportedOperationException("Cannot change operator status of " + this.getClass().getName()); ++ } ++ ++ public CommandSourceStack asVanilla() { ++ final @Nullable ServerLevel overworld = this.server.getServer().overworld(); ++ return new CommandSourceStack( ++ new Source(this), ++ overworld == null ? Vec3.ZERO : Vec3.atLowerCornerOf(overworld.getSharedSpawnPos()), ++ Vec2.ZERO, ++ overworld, ++ 4, ++ this.getName(), ++ net.minecraft.network.chat.Component.literal(this.getName()), ++ this.server.getServer(), ++ null ++ ); ++ } ++ ++ private record Source(FeedbackForwardingSender sender) implements CommandSource { ++ @Override ++ public void sendSystemMessage(final net.minecraft.network.chat.Component message) { ++ this.sender.sendMessage(Identity.nil(), PaperAdventure.asAdventure(message)); ++ } ++ ++ @Override ++ public boolean acceptsSuccess() { ++ return true; ++ } ++ ++ @Override ++ public boolean acceptsFailure() { ++ return true; ++ } ++ ++ @Override ++ public boolean shouldInformAdmins() { ++ return false; ++ } ++ ++ @Override ++ public CommandSender getBukkitSender(final CommandSourceStack stack) { ++ return this.sender; ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 6d32505266fef119289bcf6761c1948368238eb9..9de7978c7383f8364feba82e9cd3efbfcce00e3c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2165,6 +2165,13 @@ public final class CraftServer implements Server { + return this.console.console; + } + ++ // Paper start ++ @Override ++ public CommandSender createCommandSender(final java.util.function.Consumer feedback) { ++ return new io.papermc.paper.commands.FeedbackForwardingSender(feedback, this); ++ } ++ // Paper end ++ + public EntityMetadataStore getEntityMetadata() { + return this.entityMetadata; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java +index 7f22950ae61436e91a59cd29a345809c42bbe739..1e3091687735b461d3b6a313ab8761127981d3e8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java +@@ -12,7 +12,7 @@ import org.bukkit.permissions.PermissionAttachmentInfo; + import org.bukkit.plugin.Plugin; + + public abstract class ServerCommandSender implements CommandSender { +- private final PermissibleBase perm; ++ public final PermissibleBase perm; // Paper + private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers + + protected ServerCommandSender() { +diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +index 4e81c26fdbd089961b2577168c716bf29d504d40..a35e2d2f53e8308d51e5a07b34c56d05a707bc14 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +@@ -81,6 +81,11 @@ public final class VanillaCommandWrapper extends BukkitCommand { + if (sender instanceof ProxiedCommandSender) { + return ((ProxiedNativeCommandSender) sender).getHandle(); + } ++ // Paper start ++ if (sender instanceof io.papermc.paper.commands.FeedbackForwardingSender feedback) { ++ return feedback.asVanilla(); ++ } ++ // Paper end + + throw new IllegalArgumentException("Cannot make " + sender + " a vanilla command listener"); + } diff --git a/patches/server/0653-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch b/patches/server/0653-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch deleted file mode 100644 index 027285c2b1..0000000000 --- a/patches/server/0653-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Mon, 12 Jul 2021 12:28:29 +0100 -Subject: [PATCH] Use a CHM for StructureTemplate.Pallete cache - -fixes a CME due to this collection being shared across threads - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -index e7900e7e8263cae131dad2427fb2bfdadf5b8d14..b120949667ae0169a667b329b3cabbd79a0a5bda 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -@@ -889,7 +889,7 @@ public class StructureTemplate { - public static final class Palette { - - private final List blocks; -- private final Map> cache = Maps.newHashMap(); -+ private final Map> cache = Maps.newConcurrentMap(); // Paper - Fix CME due to this collection being shared across threads - @Nullable - private List cachedJigsaws; - diff --git a/patches/server/0654-API-for-creating-command-sender-which-forwards-feedb.patch b/patches/server/0654-API-for-creating-command-sender-which-forwards-feedb.patch deleted file mode 100644 index de6e7d2811..0000000000 --- a/patches/server/0654-API-for-creating-command-sender-which-forwards-feedb.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 1 Feb 2022 15:51:55 -0700 -Subject: [PATCH] API for creating command sender which forwards feedback - - -diff --git a/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java b/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e3a5f1ec376319bdfda87fa27ae217bff3914292 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java -@@ -0,0 +1,111 @@ -+package io.papermc.paper.commands; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import java.util.UUID; -+import java.util.function.Consumer; -+import net.kyori.adventure.audience.MessageType; -+import net.kyori.adventure.identity.Identity; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -+import net.minecraft.commands.CommandSource; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.phys.Vec2; -+import net.minecraft.world.phys.Vec3; -+import org.bukkit.command.CommandSender; -+import org.bukkit.craftbukkit.CraftServer; -+import org.bukkit.craftbukkit.command.ServerCommandSender; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public final class FeedbackForwardingSender extends ServerCommandSender { -+ private final Consumer feedback; -+ private final CraftServer server; -+ -+ public FeedbackForwardingSender(final Consumer feedback, final CraftServer server) { -+ super(((ServerCommandSender) server.getConsoleSender()).perm); -+ this.server = server; -+ this.feedback = feedback; -+ } -+ -+ @Override -+ public void sendMessage(final String message) { -+ this.sendMessage(LegacyComponentSerializer.legacySection().deserialize(message)); -+ } -+ -+ @Override -+ public void sendMessage(final String... messages) { -+ for (final String message : messages) { -+ this.sendMessage(message); -+ } -+ } -+ -+ @Override -+ public void sendMessage(final Identity identity, final Component message, final MessageType type) { -+ this.feedback.accept(message); -+ } -+ -+ @Override -+ public String getName() { -+ return "FeedbackForwardingSender"; -+ } -+ -+ @Override -+ public Component name() { -+ return Component.text(this.getName()); -+ } -+ -+ @Override -+ public boolean isOp() { -+ return true; -+ } -+ -+ @Override -+ public void setOp(final boolean value) { -+ throw new UnsupportedOperationException("Cannot change operator status of " + this.getClass().getName()); -+ } -+ -+ public CommandSourceStack asVanilla() { -+ final @Nullable ServerLevel overworld = this.server.getServer().overworld(); -+ return new CommandSourceStack( -+ new Source(this), -+ overworld == null ? Vec3.ZERO : Vec3.atLowerCornerOf(overworld.getSharedSpawnPos()), -+ Vec2.ZERO, -+ overworld, -+ 4, -+ this.getName(), -+ net.minecraft.network.chat.Component.literal(this.getName()), -+ this.server.getServer(), -+ null -+ ); -+ } -+ -+ private record Source(FeedbackForwardingSender sender) implements CommandSource { -+ @Override -+ public void sendSystemMessage(final net.minecraft.network.chat.Component message) { -+ this.sender.sendMessage(Identity.nil(), PaperAdventure.asAdventure(message)); -+ } -+ -+ @Override -+ public boolean acceptsSuccess() { -+ return true; -+ } -+ -+ @Override -+ public boolean acceptsFailure() { -+ return true; -+ } -+ -+ @Override -+ public boolean shouldInformAdmins() { -+ return false; -+ } -+ -+ @Override -+ public CommandSender getBukkitSender(final CommandSourceStack stack) { -+ return this.sender; -+ } -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index d30c1e853bb2e27922a00d890dffca153cdcbe97..93811e7770546c202085487642699e0c74b9f498 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2166,6 +2166,13 @@ public final class CraftServer implements Server { - return this.console.console; - } - -+ // Paper start -+ @Override -+ public CommandSender createCommandSender(final java.util.function.Consumer feedback) { -+ return new io.papermc.paper.commands.FeedbackForwardingSender(feedback, this); -+ } -+ // Paper end -+ - public EntityMetadataStore getEntityMetadata() { - return this.entityMetadata; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java -index 7f22950ae61436e91a59cd29a345809c42bbe739..1e3091687735b461d3b6a313ab8761127981d3e8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java -@@ -12,7 +12,7 @@ import org.bukkit.permissions.PermissionAttachmentInfo; - import org.bukkit.plugin.Plugin; - - public abstract class ServerCommandSender implements CommandSender { -- private final PermissibleBase perm; -+ public final PermissibleBase perm; // Paper - private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers - - protected ServerCommandSender() { -diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -index 4e81c26fdbd089961b2577168c716bf29d504d40..a35e2d2f53e8308d51e5a07b34c56d05a707bc14 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -@@ -81,6 +81,11 @@ public final class VanillaCommandWrapper extends BukkitCommand { - if (sender instanceof ProxiedCommandSender) { - return ((ProxiedNativeCommandSender) sender).getHandle(); - } -+ // Paper start -+ if (sender instanceof io.papermc.paper.commands.FeedbackForwardingSender feedback) { -+ return feedback.asVanilla(); -+ } -+ // Paper end - - throw new IllegalArgumentException("Cannot make " + sender + " a vanilla command listener"); - } diff --git a/patches/server/0654-Add-missing-structure-set-seed-configs.patch b/patches/server/0654-Add-missing-structure-set-seed-configs.patch new file mode 100644 index 0000000000..8677197bdc --- /dev/null +++ b/patches/server/0654-Add-missing-structure-set-seed-configs.patch @@ -0,0 +1,399 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 13 Jan 2022 23:05:53 -0800 +Subject: [PATCH] Add missing structure set seed configs + +The 4 missing structure set seed configs are strongholds, mineshafts, +buried treasure, and ancient cities. + +Strongholds use a ring placement scheme which isn't random so they +utilize the world seed by default, this adds a config to override it +for just generating the ring positions. + +Mineshafts and Buried Treasure structure sets are special cases +where the "salt" that can be defined for them via datapacks has 0 +effect because the difference between the spacing and separation is 1 +which is used as the upper bound in the random with salt. So the random +always returns the same int (0) so the salt has no effect. This adds +seeds/salts to the frequency reducer which has a similar effect. + +Co-authored-by: William Blake Galbreath + +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +index fc8e3edd9734fa7b69f0fc6b4eefd8a704e451cf..31c5f54c90d6e35875f762747f8618e58e2eed91 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -573,7 +573,7 @@ public abstract class ChunkGenerator { + } + } + +- if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z)) { ++ if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z, structureplacement instanceof net.minecraft.world.level.chunk.ChunkGeneratorStructureState.KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs + if (list.size() == 1) { + this.tryGenerateStructure((StructureSet.StructureSelectionEntry) list.get(0), structureAccessor, registryManager, randomstate, structureTemplateManager, placementCalculator.getLevelSeed(), chunk, chunkcoordintpair, sectionposition); + } else { +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java +index ed779a03e2ce7684428600dac4f2e92ab002f29f..a20520a6bd28bae1cee82258ac49d9753faba2bd 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java +@@ -50,13 +50,14 @@ public class ChunkGeneratorStructureState { + private final Map>> ringPositions = new Object2ObjectArrayMap(); + private boolean hasGeneratedPositions; + private final List> possibleStructureSets; ++ public final SpigotWorldConfig conf; // Paper - Add missing structure set seed configs + + public static ChunkGeneratorStructureState createForFlat(RandomState randomstate, long i, BiomeSource worldchunkmanager, Stream> stream, SpigotWorldConfig conf) { // Spigot + List> list = stream.filter((holder) -> { + return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder.value(), worldchunkmanager); + }).toList(); + +- return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf)); // Spigot ++ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot + } + + public static ChunkGeneratorStructureState createForNormal(RandomState randomstate, long i, BiomeSource worldchunkmanager, HolderLookup holderlookup, SpigotWorldConfig conf) { // Spigot +@@ -64,14 +65,24 @@ public class ChunkGeneratorStructureState { + return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder_c.value(), worldchunkmanager); + }).collect(Collectors.toUnmodifiableList()); + +- return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, i, ChunkGeneratorStructureState.injectSpigot(list, conf)); // Spigot ++ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, i, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot + } ++ // Paper start - Add missing structure set seed configs; horrible hack because spigot creates a ton of direct Holders which lose track of the identifying key ++ public static final class KeyedRandomSpreadStructurePlacement extends RandomSpreadStructurePlacement { ++ public final net.minecraft.resources.ResourceKey key; ++ public KeyedRandomSpreadStructurePlacement(net.minecraft.resources.ResourceKey key, net.minecraft.core.Vec3i locateOffset, FrequencyReductionMethod frequencyReductionMethod, float frequency, int salt, java.util.Optional exclusionZone, int spacing, int separation, net.minecraft.world.level.levelgen.structure.placement.RandomSpreadType spreadType) { ++ super(locateOffset, frequencyReductionMethod, frequency, salt, exclusionZone, spacing, separation, spreadType); ++ this.key = key; ++ } ++ } ++ // Paper end - Add missing structure set seed configs + + // Spigot start + private static List> injectSpigot(List> list, SpigotWorldConfig conf) { + return list.stream().map((holder) -> { + StructureSet structureset = holder.value(); +- if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig) { ++ final Holder newHolder; // Paper - Add missing structure set seed configs ++ if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig && holder.unwrapKey().orElseThrow().location().getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)) { // Paper - Add missing structure set seed configs; check namespace cause datapacks could add structure sets with the same path + String name = holder.unwrapKey().orElseThrow().location().getPath(); + int seed = randomConfig.salt; + +@@ -118,11 +129,27 @@ public class ChunkGeneratorStructureState { + case "villages": + seed = conf.villageSeed; + break; ++ // Paper start - Add missing structure set seed configs ++ case "ancient_cities": ++ seed = conf.ancientCitySeed; ++ break; ++ case "trail_ruins": ++ seed = conf.trailRuinsSeed; ++ break; ++ case "trial_chambers": ++ seed = conf.trialChambersSeed; ++ break; ++ // Paper end - Add missing structure set seed configs + } + +- structureset = new StructureSet(structureset.structures(), new RandomSpreadStructurePlacement(randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType())); ++ // Paper start - Add missing structure set seed configs ++ structureset = new StructureSet(structureset.structures(), new KeyedRandomSpreadStructurePlacement(holder.unwrapKey().orElseThrow(), randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType())); ++ newHolder = Holder.direct(structureset); // I really wish we didn't have to do this here ++ } else { ++ newHolder = holder; + } +- return Holder.direct(structureset); ++ return newHolder; ++ // Paper end - Add missing structure set seed configs + }).collect(Collectors.toUnmodifiableList()); + } + // Spigot end +@@ -139,12 +166,13 @@ public class ChunkGeneratorStructureState { + return stream.anyMatch(set::contains); + } + +- private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List> structureSets) { ++ private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List> structureSets, SpigotWorldConfig conf) { // Paper - Add missing structure set seed configs + this.randomState = noiseConfig; + this.levelSeed = structureSeed; + this.biomeSource = biomeSource; + this.concentricRingsSeed = concentricRingSeed; + this.possibleStructureSets = structureSets; ++ this.conf = conf; // Paper - Add missing structure set seed configs + } + + public List> possibleStructureSets() { +@@ -198,7 +226,13 @@ public class ChunkGeneratorStructureState { + HolderSet holderset = placement.preferredBiomes(); + RandomSource randomsource = RandomSource.create(); + ++ // Paper start - Add missing structure set seed configs ++ if (this.conf.strongholdSeed != null && structureSetEntry.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) { ++ randomsource.setSeed(this.conf.strongholdSeed); ++ } else { ++ // Paper end - Add missing structure set seed configs + randomsource.setSeed(this.concentricRingsSeed); ++ } // Paper - Add missing structure set seed configs + double d0 = randomsource.nextDouble() * Math.PI * 2.0D; + int l = 0; + int i1 = 0; +@@ -275,7 +309,7 @@ public class ChunkGeneratorStructureState { + + for (int l = centerChunkX - chunkCount; l <= centerChunkX + chunkCount; ++l) { + for (int i1 = centerChunkZ - chunkCount; i1 <= centerChunkZ + chunkCount; ++i1) { +- if (structureplacement.isStructureChunk(this, l, i1)) { ++ if (structureplacement.isStructureChunk(this, l, i1, structureplacement instanceof KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs + return true; + } + } +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java +index 953ab7638f7242b5a11dd1de8786172443a0558c..5f354b333a39b873915bedd57b647355ae5bdf56 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java +@@ -74,6 +74,20 @@ public class StructureCheck { + this.fixerUpper = dataFixer; + } + ++ // Paper start - add missing structure salt configs ++ @Nullable ++ private Integer getSaltOverride(Structure type) { ++ if (this.heightAccessor instanceof net.minecraft.server.level.ServerLevel serverLevel) { ++ if (type instanceof net.minecraft.world.level.levelgen.structure.structures.MineshaftStructure) { ++ return serverLevel.spigotConfig.mineshaftSeed; ++ } else if (type instanceof net.minecraft.world.level.levelgen.structure.structures.BuriedTreasureStructure) { ++ return serverLevel.spigotConfig.buriedTreasureSeed; ++ } ++ } ++ return null; ++ } ++ // Paper end - add missing structure seed configs ++ + public StructureCheckResult checkStart(ChunkPos pos, Structure type, StructurePlacement placement, boolean skipReferencedStructures) { + long l = pos.toLong(); + Object2IntMap object2IntMap = this.loadedChunks.get(l); +@@ -83,7 +97,7 @@ public class StructureCheck { + StructureCheckResult structureCheckResult = this.tryLoadFromStorage(pos, type, skipReferencedStructures, l); + if (structureCheckResult != null) { + return structureCheckResult; +- } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed)) { ++ } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed, this.getSaltOverride(type))) { // Paper - add missing structure seed configs + return StructureCheckResult.START_NOT_PRESENT; + } else { + boolean bl = this.featureChecks +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java +index a4c34e9415632354d33668a38d06453ada4d3c77..cbf13e4f2da6a27619e9bc9a7cd73bb6e69cad2a 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java +@@ -79,14 +79,30 @@ public abstract class StructurePlacement { + return this.exclusionZone; + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add missing structure set seed configs + public boolean isStructureChunk(ChunkGeneratorStructureState calculator, int chunkX, int chunkZ) { ++ // Paper start - Add missing structure set seed configs ++ return this.isStructureChunk(calculator, chunkX, chunkZ, null); ++ } ++ public boolean isStructureChunk(ChunkGeneratorStructureState calculator, int chunkX, int chunkZ, @org.jetbrains.annotations.Nullable net.minecraft.resources.ResourceKey structureSetKey) { ++ Integer saltOverride = null; ++ if (structureSetKey != null) { ++ if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.MINESHAFTS) { ++ saltOverride = calculator.conf.mineshaftSeed; ++ } else if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.BURIED_TREASURES) { ++ saltOverride = calculator.conf.buriedTreasureSeed; ++ } ++ } ++ // Paper end - Add missing structure set seed configs + return this.isPlacementChunk(calculator, chunkX, chunkZ) +- && this.applyAdditionalChunkRestrictions(chunkX, chunkZ, calculator.getLevelSeed()) ++ && this.applyAdditionalChunkRestrictions(chunkX, chunkZ, calculator.getLevelSeed(), saltOverride) // Paper - Add missing structure set seed configs + && this.applyInteractionsWithOtherStructures(calculator, chunkX, chunkZ); + } + +- public boolean applyAdditionalChunkRestrictions(int chunkX, int chunkZ, long seed) { +- return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency); ++ // Paper start - Add missing structure set seed configs ++ public boolean applyAdditionalChunkRestrictions(int chunkX, int chunkZ, long seed, @org.jetbrains.annotations.Nullable Integer saltOverride) { ++ return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency, saltOverride); ++ // Paper end - Add missing structure set seed configs + } + + public boolean applyInteractionsWithOtherStructures(ChunkGeneratorStructureState calculator, int centerChunkX, int centerChunkZ) { +@@ -101,25 +117,31 @@ public abstract class StructurePlacement { + + public abstract StructurePlacementType type(); + +- private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { ++ private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here + WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); + worldgenRandom.setLargeFeatureWithSalt(seed, salt, chunkX, chunkZ); + return worldgenRandom.nextFloat() < frequency; + } + +- private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency) { ++ private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs + WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); ++ if (saltOverride == null) { // Paper - Add missing structure set seed configs + worldgenRandom.setLargeFeatureSeed(seed, chunkX, chunkZ); ++ // Paper start - Add missing structure set seed configs ++ } else { ++ worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride); ++ } ++ // Paper end - Add missing structure set seed configs + return worldgenRandom.nextDouble() < (double)frequency; + } + +- private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { ++ private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs + WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); +- worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, 10387320); ++ worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride != null ? saltOverride : HIGHLY_ARBITRARY_RANDOM_SALT); // Paper - Add missing structure set seed configs + return worldgenRandom.nextFloat() < frequency; + } + +- private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { ++ private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here + int i = chunkX >> 4; + int j = chunkZ >> 4; + WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); +@@ -147,7 +169,7 @@ public abstract class StructurePlacement { + + @FunctionalInterface + public interface FrequencyReducer { +- boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance); ++ boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride); // Paper - Add missing structure set seed configs + } + + public static enum FrequencyReductionMethod implements StringRepresentable { +@@ -167,8 +189,8 @@ public abstract class StructurePlacement { + this.reducer = generationPredicate; + } + +- public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance) { +- return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance); ++ public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs ++ return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance, saltOverride); // Paper - Add missing structure set seed configs + } + + @Override +diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java +index e76f96a5c48d1eda2f9bbb3e11dd79f23f9ab75c..2b263246135c85aa225120519e9702a628773935 100644 +--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java ++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java +@@ -322,6 +322,18 @@ public class SpigotWorldConfig + public int mansionSeed; + public int fossilSeed; + public int portalSeed; ++ // Paper start - add missing structure set configs ++ public int ancientCitySeed; ++ public int trailRuinsSeed; ++ public int trialChambersSeed; ++ public int buriedTreasureSeed; ++ public Integer mineshaftSeed; ++ public Long strongholdSeed; ++ private N getSeed(String path, java.util.function.Function toNumberFunc) { ++ final String value = this.getString(path, "default"); ++ return org.apache.commons.lang3.math.NumberUtils.isParsable(value) ? toNumberFunc.apply(value) : null; ++ } ++ // Paper end + private void initWorldGenSeeds() + { + this.villageSeed = this.getInt( "seed-village", 10387312 ); +@@ -339,6 +351,14 @@ public class SpigotWorldConfig + this.mansionSeed = this.getInt( "seed-mansion", 10387319 ); + this.fossilSeed = this.getInt( "seed-fossil", 14357921 ); + this.portalSeed = this.getInt( "seed-portal", 34222645 ); ++ // Paper start - add missing structure set configs ++ this.ancientCitySeed = this.getInt("seed-ancientcity", 20083232); ++ this.trailRuinsSeed = this.getInt("seed-trailruins", 83469867); ++ this.trialChambersSeed = this.getInt("seed-trialchambers", 94251327); ++ this.buriedTreasureSeed = this.getInt("seed-buriedtreasure", 10387320); // StructurePlacement#HIGHLY_ARBITRARY_RANDOM_SALT ++ this.mineshaftSeed = this.getSeed("seed-mineshaft", Integer::parseInt); ++ this.strongholdSeed = this.getSeed("seed-stronghold", Long::parseLong); ++ // Paper end + this.log( "Custom Map Seeds: Village: " + this.villageSeed + " Desert: " + this.desertSeed + " Igloo: " + this.iglooSeed + " Jungle: " + this.jungleSeed + " Swamp: " + this.swampSeed + " Monument: " + this.monumentSeed + + " Ocean: " + this.oceanSeed + " Shipwreck: " + this.shipwreckSeed + " End City: " + this.endCitySeed + " Slime: " + this.slimeSeed + " Nether: " + this.netherSeed + " Mansion: " + this.mansionSeed + " Fossil: " + this.fossilSeed + " Portal: " + this.portalSeed ); + } +diff --git a/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java b/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cc1fb5ae9e0898735771c6163c9b90658fb61eed +--- /dev/null ++++ b/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java +@@ -0,0 +1,77 @@ ++package io.papermc.paper.world.structure; ++ ++import io.papermc.paper.configuration.PaperConfigurations; ++import java.io.File; ++import java.lang.reflect.Field; ++import net.minecraft.core.Registry; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.world.level.levelgen.structure.BuiltinStructureSets; ++import net.minecraft.world.level.levelgen.structure.StructureSet; ++import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; ++import org.bukkit.configuration.file.YamlConfiguration; ++import org.bukkit.support.RegistryHelper; ++import org.bukkit.support.environment.AllFeatures; ++import org.jetbrains.annotations.NotNull; ++import org.junit.jupiter.api.Test; ++import org.spigotmc.SpigotConfig; ++import org.spigotmc.SpigotWorldConfig; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++ ++@AllFeatures ++public class StructureSeedConfigTest { ++ ++ @Test ++ public void checkStructureSeedDefaults() throws ReflectiveOperationException { ++ SpigotConfig.config = new YamlConfiguration() { ++ @Override ++ public void save(final @NotNull File file) { ++ // no-op ++ } ++ }; ++ final SpigotWorldConfig config = PaperConfigurations.SPIGOT_WORLD_DEFAULTS.get(); ++ ++ ++ final Registry structureSets = RegistryHelper.getRegistry().lookupOrThrow(Registries.STRUCTURE_SET); ++ for (final ResourceKey setKey : structureSets.registryKeySet()) { ++ assertEquals(ResourceLocation.DEFAULT_NAMESPACE, setKey.location().getNamespace()); ++ final StructureSet set = structureSets.getValueOrThrow(setKey); ++ if (setKey == BuiltinStructureSets.STRONGHOLDS) { // special case due to seed matching world seed ++ assertEquals(0, set.placement().salt); ++ continue; ++ } ++ int salt = switch (setKey.location().getPath()) { ++ case "villages" -> config.villageSeed; ++ case "desert_pyramids" -> config.desertSeed; ++ case "igloos" -> config.iglooSeed; ++ case "jungle_temples" -> config.jungleSeed; ++ case "swamp_huts" -> config.swampSeed; ++ case "pillager_outposts" -> config.outpostSeed; ++ case "ocean_monuments" -> config.monumentSeed; ++ case "woodland_mansions" -> config.mansionSeed; ++ case "buried_treasures" -> config.buriedTreasureSeed; ++ case "mineshafts" -> config.mineshaftSeed == null ? 0 : config.mineshaftSeed; // mineshaft seed is set differently ++ case "ruined_portals" -> config.portalSeed; ++ case "shipwrecks" -> config.shipwreckSeed; ++ case "ocean_ruins" -> config.oceanSeed; ++ case "nether_complexes" -> config.netherSeed; ++ case "nether_fossils" -> config.fossilSeed; ++ case "end_cities" -> config.endCitySeed; ++ case "ancient_cities" -> config.ancientCitySeed; ++ case "trail_ruins" -> config.trailRuinsSeed; ++ case "trial_chambers" -> config.trialChambersSeed; ++ default -> throw new AssertionError("Missing structure set seed in SpigotWorldConfig for " + setKey); ++ }; ++ if (setKey == BuiltinStructureSets.BURIED_TREASURES) { ++ final Field field = StructurePlacement.class.getDeclaredField("HIGHLY_ARBITRARY_RANDOM_SALT"); ++ field.trySetAccessible(); ++ assertEquals(0, set.placement().salt); ++ assertEquals(field.get(null), salt, "Mismatched default seed for " + setKey + ". Should be " + field.get(null)); ++ continue; ++ } ++ assertEquals(set.placement().salt, salt, "Mismatched default seed for " + setKey + ". Should be " + set.placement().salt); ++ } ++ } ++} diff --git a/patches/server/0655-Add-missing-structure-set-seed-configs.patch b/patches/server/0655-Add-missing-structure-set-seed-configs.patch deleted file mode 100644 index 8677197bdc..0000000000 --- a/patches/server/0655-Add-missing-structure-set-seed-configs.patch +++ /dev/null @@ -1,399 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 13 Jan 2022 23:05:53 -0800 -Subject: [PATCH] Add missing structure set seed configs - -The 4 missing structure set seed configs are strongholds, mineshafts, -buried treasure, and ancient cities. - -Strongholds use a ring placement scheme which isn't random so they -utilize the world seed by default, this adds a config to override it -for just generating the ring positions. - -Mineshafts and Buried Treasure structure sets are special cases -where the "salt" that can be defined for them via datapacks has 0 -effect because the difference between the spacing and separation is 1 -which is used as the upper bound in the random with salt. So the random -always returns the same int (0) so the salt has no effect. This adds -seeds/salts to the frequency reducer which has a similar effect. - -Co-authored-by: William Blake Galbreath - -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index fc8e3edd9734fa7b69f0fc6b4eefd8a704e451cf..31c5f54c90d6e35875f762747f8618e58e2eed91 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -573,7 +573,7 @@ public abstract class ChunkGenerator { - } - } - -- if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z)) { -+ if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z, structureplacement instanceof net.minecraft.world.level.chunk.ChunkGeneratorStructureState.KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs - if (list.size() == 1) { - this.tryGenerateStructure((StructureSet.StructureSelectionEntry) list.get(0), structureAccessor, registryManager, randomstate, structureTemplateManager, placementCalculator.getLevelSeed(), chunk, chunkcoordintpair, sectionposition); - } else { -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java -index ed779a03e2ce7684428600dac4f2e92ab002f29f..a20520a6bd28bae1cee82258ac49d9753faba2bd 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java -@@ -50,13 +50,14 @@ public class ChunkGeneratorStructureState { - private final Map>> ringPositions = new Object2ObjectArrayMap(); - private boolean hasGeneratedPositions; - private final List> possibleStructureSets; -+ public final SpigotWorldConfig conf; // Paper - Add missing structure set seed configs - - public static ChunkGeneratorStructureState createForFlat(RandomState randomstate, long i, BiomeSource worldchunkmanager, Stream> stream, SpigotWorldConfig conf) { // Spigot - List> list = stream.filter((holder) -> { - return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder.value(), worldchunkmanager); - }).toList(); - -- return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf)); // Spigot -+ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot - } - - public static ChunkGeneratorStructureState createForNormal(RandomState randomstate, long i, BiomeSource worldchunkmanager, HolderLookup holderlookup, SpigotWorldConfig conf) { // Spigot -@@ -64,14 +65,24 @@ public class ChunkGeneratorStructureState { - return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder_c.value(), worldchunkmanager); - }).collect(Collectors.toUnmodifiableList()); - -- return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, i, ChunkGeneratorStructureState.injectSpigot(list, conf)); // Spigot -+ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, i, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot - } -+ // Paper start - Add missing structure set seed configs; horrible hack because spigot creates a ton of direct Holders which lose track of the identifying key -+ public static final class KeyedRandomSpreadStructurePlacement extends RandomSpreadStructurePlacement { -+ public final net.minecraft.resources.ResourceKey key; -+ public KeyedRandomSpreadStructurePlacement(net.minecraft.resources.ResourceKey key, net.minecraft.core.Vec3i locateOffset, FrequencyReductionMethod frequencyReductionMethod, float frequency, int salt, java.util.Optional exclusionZone, int spacing, int separation, net.minecraft.world.level.levelgen.structure.placement.RandomSpreadType spreadType) { -+ super(locateOffset, frequencyReductionMethod, frequency, salt, exclusionZone, spacing, separation, spreadType); -+ this.key = key; -+ } -+ } -+ // Paper end - Add missing structure set seed configs - - // Spigot start - private static List> injectSpigot(List> list, SpigotWorldConfig conf) { - return list.stream().map((holder) -> { - StructureSet structureset = holder.value(); -- if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig) { -+ final Holder newHolder; // Paper - Add missing structure set seed configs -+ if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig && holder.unwrapKey().orElseThrow().location().getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)) { // Paper - Add missing structure set seed configs; check namespace cause datapacks could add structure sets with the same path - String name = holder.unwrapKey().orElseThrow().location().getPath(); - int seed = randomConfig.salt; - -@@ -118,11 +129,27 @@ public class ChunkGeneratorStructureState { - case "villages": - seed = conf.villageSeed; - break; -+ // Paper start - Add missing structure set seed configs -+ case "ancient_cities": -+ seed = conf.ancientCitySeed; -+ break; -+ case "trail_ruins": -+ seed = conf.trailRuinsSeed; -+ break; -+ case "trial_chambers": -+ seed = conf.trialChambersSeed; -+ break; -+ // Paper end - Add missing structure set seed configs - } - -- structureset = new StructureSet(structureset.structures(), new RandomSpreadStructurePlacement(randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType())); -+ // Paper start - Add missing structure set seed configs -+ structureset = new StructureSet(structureset.structures(), new KeyedRandomSpreadStructurePlacement(holder.unwrapKey().orElseThrow(), randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType())); -+ newHolder = Holder.direct(structureset); // I really wish we didn't have to do this here -+ } else { -+ newHolder = holder; - } -- return Holder.direct(structureset); -+ return newHolder; -+ // Paper end - Add missing structure set seed configs - }).collect(Collectors.toUnmodifiableList()); - } - // Spigot end -@@ -139,12 +166,13 @@ public class ChunkGeneratorStructureState { - return stream.anyMatch(set::contains); - } - -- private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List> structureSets) { -+ private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List> structureSets, SpigotWorldConfig conf) { // Paper - Add missing structure set seed configs - this.randomState = noiseConfig; - this.levelSeed = structureSeed; - this.biomeSource = biomeSource; - this.concentricRingsSeed = concentricRingSeed; - this.possibleStructureSets = structureSets; -+ this.conf = conf; // Paper - Add missing structure set seed configs - } - - public List> possibleStructureSets() { -@@ -198,7 +226,13 @@ public class ChunkGeneratorStructureState { - HolderSet holderset = placement.preferredBiomes(); - RandomSource randomsource = RandomSource.create(); - -+ // Paper start - Add missing structure set seed configs -+ if (this.conf.strongholdSeed != null && structureSetEntry.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) { -+ randomsource.setSeed(this.conf.strongholdSeed); -+ } else { -+ // Paper end - Add missing structure set seed configs - randomsource.setSeed(this.concentricRingsSeed); -+ } // Paper - Add missing structure set seed configs - double d0 = randomsource.nextDouble() * Math.PI * 2.0D; - int l = 0; - int i1 = 0; -@@ -275,7 +309,7 @@ public class ChunkGeneratorStructureState { - - for (int l = centerChunkX - chunkCount; l <= centerChunkX + chunkCount; ++l) { - for (int i1 = centerChunkZ - chunkCount; i1 <= centerChunkZ + chunkCount; ++i1) { -- if (structureplacement.isStructureChunk(this, l, i1)) { -+ if (structureplacement.isStructureChunk(this, l, i1, structureplacement instanceof KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs - return true; - } - } -diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java -index 953ab7638f7242b5a11dd1de8786172443a0558c..5f354b333a39b873915bedd57b647355ae5bdf56 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java -@@ -74,6 +74,20 @@ public class StructureCheck { - this.fixerUpper = dataFixer; - } - -+ // Paper start - add missing structure salt configs -+ @Nullable -+ private Integer getSaltOverride(Structure type) { -+ if (this.heightAccessor instanceof net.minecraft.server.level.ServerLevel serverLevel) { -+ if (type instanceof net.minecraft.world.level.levelgen.structure.structures.MineshaftStructure) { -+ return serverLevel.spigotConfig.mineshaftSeed; -+ } else if (type instanceof net.minecraft.world.level.levelgen.structure.structures.BuriedTreasureStructure) { -+ return serverLevel.spigotConfig.buriedTreasureSeed; -+ } -+ } -+ return null; -+ } -+ // Paper end - add missing structure seed configs -+ - public StructureCheckResult checkStart(ChunkPos pos, Structure type, StructurePlacement placement, boolean skipReferencedStructures) { - long l = pos.toLong(); - Object2IntMap object2IntMap = this.loadedChunks.get(l); -@@ -83,7 +97,7 @@ public class StructureCheck { - StructureCheckResult structureCheckResult = this.tryLoadFromStorage(pos, type, skipReferencedStructures, l); - if (structureCheckResult != null) { - return structureCheckResult; -- } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed)) { -+ } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed, this.getSaltOverride(type))) { // Paper - add missing structure seed configs - return StructureCheckResult.START_NOT_PRESENT; - } else { - boolean bl = this.featureChecks -diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java -index a4c34e9415632354d33668a38d06453ada4d3c77..cbf13e4f2da6a27619e9bc9a7cd73bb6e69cad2a 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java -@@ -79,14 +79,30 @@ public abstract class StructurePlacement { - return this.exclusionZone; - } - -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add missing structure set seed configs - public boolean isStructureChunk(ChunkGeneratorStructureState calculator, int chunkX, int chunkZ) { -+ // Paper start - Add missing structure set seed configs -+ return this.isStructureChunk(calculator, chunkX, chunkZ, null); -+ } -+ public boolean isStructureChunk(ChunkGeneratorStructureState calculator, int chunkX, int chunkZ, @org.jetbrains.annotations.Nullable net.minecraft.resources.ResourceKey structureSetKey) { -+ Integer saltOverride = null; -+ if (structureSetKey != null) { -+ if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.MINESHAFTS) { -+ saltOverride = calculator.conf.mineshaftSeed; -+ } else if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.BURIED_TREASURES) { -+ saltOverride = calculator.conf.buriedTreasureSeed; -+ } -+ } -+ // Paper end - Add missing structure set seed configs - return this.isPlacementChunk(calculator, chunkX, chunkZ) -- && this.applyAdditionalChunkRestrictions(chunkX, chunkZ, calculator.getLevelSeed()) -+ && this.applyAdditionalChunkRestrictions(chunkX, chunkZ, calculator.getLevelSeed(), saltOverride) // Paper - Add missing structure set seed configs - && this.applyInteractionsWithOtherStructures(calculator, chunkX, chunkZ); - } - -- public boolean applyAdditionalChunkRestrictions(int chunkX, int chunkZ, long seed) { -- return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency); -+ // Paper start - Add missing structure set seed configs -+ public boolean applyAdditionalChunkRestrictions(int chunkX, int chunkZ, long seed, @org.jetbrains.annotations.Nullable Integer saltOverride) { -+ return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency, saltOverride); -+ // Paper end - Add missing structure set seed configs - } - - public boolean applyInteractionsWithOtherStructures(ChunkGeneratorStructureState calculator, int centerChunkX, int centerChunkZ) { -@@ -101,25 +117,31 @@ public abstract class StructurePlacement { - - public abstract StructurePlacementType type(); - -- private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { -+ private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); - worldgenRandom.setLargeFeatureWithSalt(seed, salt, chunkX, chunkZ); - return worldgenRandom.nextFloat() < frequency; - } - -- private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency) { -+ private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); -+ if (saltOverride == null) { // Paper - Add missing structure set seed configs - worldgenRandom.setLargeFeatureSeed(seed, chunkX, chunkZ); -+ // Paper start - Add missing structure set seed configs -+ } else { -+ worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride); -+ } -+ // Paper end - Add missing structure set seed configs - return worldgenRandom.nextDouble() < (double)frequency; - } - -- private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { -+ private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); -- worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, 10387320); -+ worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride != null ? saltOverride : HIGHLY_ARBITRARY_RANDOM_SALT); // Paper - Add missing structure set seed configs - return worldgenRandom.nextFloat() < frequency; - } - -- private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) { -+ private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here - int i = chunkX >> 4; - int j = chunkZ >> 4; - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); -@@ -147,7 +169,7 @@ public abstract class StructurePlacement { - - @FunctionalInterface - public interface FrequencyReducer { -- boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance); -+ boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride); // Paper - Add missing structure set seed configs - } - - public static enum FrequencyReductionMethod implements StringRepresentable { -@@ -167,8 +189,8 @@ public abstract class StructurePlacement { - this.reducer = generationPredicate; - } - -- public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance) { -- return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance); -+ public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs -+ return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance, saltOverride); // Paper - Add missing structure set seed configs - } - - @Override -diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java -index e76f96a5c48d1eda2f9bbb3e11dd79f23f9ab75c..2b263246135c85aa225120519e9702a628773935 100644 ---- a/src/main/java/org/spigotmc/SpigotWorldConfig.java -+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java -@@ -322,6 +322,18 @@ public class SpigotWorldConfig - public int mansionSeed; - public int fossilSeed; - public int portalSeed; -+ // Paper start - add missing structure set configs -+ public int ancientCitySeed; -+ public int trailRuinsSeed; -+ public int trialChambersSeed; -+ public int buriedTreasureSeed; -+ public Integer mineshaftSeed; -+ public Long strongholdSeed; -+ private N getSeed(String path, java.util.function.Function toNumberFunc) { -+ final String value = this.getString(path, "default"); -+ return org.apache.commons.lang3.math.NumberUtils.isParsable(value) ? toNumberFunc.apply(value) : null; -+ } -+ // Paper end - private void initWorldGenSeeds() - { - this.villageSeed = this.getInt( "seed-village", 10387312 ); -@@ -339,6 +351,14 @@ public class SpigotWorldConfig - this.mansionSeed = this.getInt( "seed-mansion", 10387319 ); - this.fossilSeed = this.getInt( "seed-fossil", 14357921 ); - this.portalSeed = this.getInt( "seed-portal", 34222645 ); -+ // Paper start - add missing structure set configs -+ this.ancientCitySeed = this.getInt("seed-ancientcity", 20083232); -+ this.trailRuinsSeed = this.getInt("seed-trailruins", 83469867); -+ this.trialChambersSeed = this.getInt("seed-trialchambers", 94251327); -+ this.buriedTreasureSeed = this.getInt("seed-buriedtreasure", 10387320); // StructurePlacement#HIGHLY_ARBITRARY_RANDOM_SALT -+ this.mineshaftSeed = this.getSeed("seed-mineshaft", Integer::parseInt); -+ this.strongholdSeed = this.getSeed("seed-stronghold", Long::parseLong); -+ // Paper end - this.log( "Custom Map Seeds: Village: " + this.villageSeed + " Desert: " + this.desertSeed + " Igloo: " + this.iglooSeed + " Jungle: " + this.jungleSeed + " Swamp: " + this.swampSeed + " Monument: " + this.monumentSeed - + " Ocean: " + this.oceanSeed + " Shipwreck: " + this.shipwreckSeed + " End City: " + this.endCitySeed + " Slime: " + this.slimeSeed + " Nether: " + this.netherSeed + " Mansion: " + this.mansionSeed + " Fossil: " + this.fossilSeed + " Portal: " + this.portalSeed ); - } -diff --git a/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java b/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cc1fb5ae9e0898735771c6163c9b90658fb61eed ---- /dev/null -+++ b/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java -@@ -0,0 +1,77 @@ -+package io.papermc.paper.world.structure; -+ -+import io.papermc.paper.configuration.PaperConfigurations; -+import java.io.File; -+import java.lang.reflect.Field; -+import net.minecraft.core.Registry; -+import net.minecraft.core.registries.Registries; -+import net.minecraft.resources.ResourceKey; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.world.level.levelgen.structure.BuiltinStructureSets; -+import net.minecraft.world.level.levelgen.structure.StructureSet; -+import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; -+import org.bukkit.configuration.file.YamlConfiguration; -+import org.bukkit.support.RegistryHelper; -+import org.bukkit.support.environment.AllFeatures; -+import org.jetbrains.annotations.NotNull; -+import org.junit.jupiter.api.Test; -+import org.spigotmc.SpigotConfig; -+import org.spigotmc.SpigotWorldConfig; -+ -+import static org.junit.jupiter.api.Assertions.assertEquals; -+ -+@AllFeatures -+public class StructureSeedConfigTest { -+ -+ @Test -+ public void checkStructureSeedDefaults() throws ReflectiveOperationException { -+ SpigotConfig.config = new YamlConfiguration() { -+ @Override -+ public void save(final @NotNull File file) { -+ // no-op -+ } -+ }; -+ final SpigotWorldConfig config = PaperConfigurations.SPIGOT_WORLD_DEFAULTS.get(); -+ -+ -+ final Registry structureSets = RegistryHelper.getRegistry().lookupOrThrow(Registries.STRUCTURE_SET); -+ for (final ResourceKey setKey : structureSets.registryKeySet()) { -+ assertEquals(ResourceLocation.DEFAULT_NAMESPACE, setKey.location().getNamespace()); -+ final StructureSet set = structureSets.getValueOrThrow(setKey); -+ if (setKey == BuiltinStructureSets.STRONGHOLDS) { // special case due to seed matching world seed -+ assertEquals(0, set.placement().salt); -+ continue; -+ } -+ int salt = switch (setKey.location().getPath()) { -+ case "villages" -> config.villageSeed; -+ case "desert_pyramids" -> config.desertSeed; -+ case "igloos" -> config.iglooSeed; -+ case "jungle_temples" -> config.jungleSeed; -+ case "swamp_huts" -> config.swampSeed; -+ case "pillager_outposts" -> config.outpostSeed; -+ case "ocean_monuments" -> config.monumentSeed; -+ case "woodland_mansions" -> config.mansionSeed; -+ case "buried_treasures" -> config.buriedTreasureSeed; -+ case "mineshafts" -> config.mineshaftSeed == null ? 0 : config.mineshaftSeed; // mineshaft seed is set differently -+ case "ruined_portals" -> config.portalSeed; -+ case "shipwrecks" -> config.shipwreckSeed; -+ case "ocean_ruins" -> config.oceanSeed; -+ case "nether_complexes" -> config.netherSeed; -+ case "nether_fossils" -> config.fossilSeed; -+ case "end_cities" -> config.endCitySeed; -+ case "ancient_cities" -> config.ancientCitySeed; -+ case "trail_ruins" -> config.trailRuinsSeed; -+ case "trial_chambers" -> config.trialChambersSeed; -+ default -> throw new AssertionError("Missing structure set seed in SpigotWorldConfig for " + setKey); -+ }; -+ if (setKey == BuiltinStructureSets.BURIED_TREASURES) { -+ final Field field = StructurePlacement.class.getDeclaredField("HIGHLY_ARBITRARY_RANDOM_SALT"); -+ field.trySetAccessible(); -+ assertEquals(0, set.placement().salt); -+ assertEquals(field.get(null), salt, "Mismatched default seed for " + setKey + ". Should be " + field.get(null)); -+ continue; -+ } -+ assertEquals(set.placement().salt, salt, "Mismatched default seed for " + setKey + ". Should be " + set.placement().salt); -+ } -+ } -+} diff --git a/patches/server/0655-Fix-cancelled-powdered-snow-bucket-placement.patch b/patches/server/0655-Fix-cancelled-powdered-snow-bucket-placement.patch new file mode 100644 index 0000000000..d1a867e605 --- /dev/null +++ b/patches/server/0655-Fix-cancelled-powdered-snow-bucket-placement.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 8 Oct 2021 13:12:58 -0700 +Subject: [PATCH] Fix cancelled powdered snow bucket placement + +Cancelling the placement of powdered snow from the powdered +snow bucket didn't revert grass that became snowy because of the +placement. + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 8c9ae9ac38def29ae4cd8944395e566e434d46d0..a100c7a53b4b1dac0a01ee65418d44297bcdb93f 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -425,7 +425,7 @@ public final class ItemStack implements DataComponentHolder { + int oldCount = this.getCount(); + ServerLevel world = (ServerLevel) context.getLevel(); + +- if (!(item instanceof BucketItem || item instanceof SolidBucketItem)) { // if not bucket ++ if (!(item instanceof BucketItem/* || item instanceof SolidBucketItem*/)) { // if not bucket // Paper - Fix cancelled powdered snow bucket placement + world.captureBlockStates = true; + // special case bonemeal + if (item == Items.BONE_MEAL) { +@@ -488,7 +488,7 @@ public final class ItemStack implements DataComponentHolder { + world.capturedBlockStates.clear(); + if (blocks.size() > 1) { + placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, enumhand, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ()); +- } else if (blocks.size() == 1) { ++ } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement + placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, enumhand, blocks.get(0), blockposition.getX(), blockposition.getY(), blockposition.getZ()); + } + diff --git a/patches/server/0656-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch b/patches/server/0656-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch new file mode 100644 index 0000000000..3f4362495a --- /dev/null +++ b/patches/server/0656-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Sat, 12 Feb 2022 12:40:50 -0700 +Subject: [PATCH] Add missing Validate calls to CraftServer#getSpawnLimit + +Copies appropriate checks from CraftWorld#getSpawnLimit + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 9de7978c7383f8364feba82e9cd3efbfcce00e3c..c1bdefbad35fd259e3d90c6e330da14c9d072090 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2342,6 +2342,8 @@ public final class CraftServer implements Server { + @Override + public int getSpawnLimit(SpawnCategory spawnCategory) { + // Paper start - Add mobcaps commands ++ Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); ++ Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory." + spawnCategory + " does not have a spawn limit."); + return this.getSpawnLimitUnsafe(spawnCategory); + } + public int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) { diff --git a/patches/server/0656-Fix-cancelled-powdered-snow-bucket-placement.patch b/patches/server/0656-Fix-cancelled-powdered-snow-bucket-placement.patch deleted file mode 100644 index d1a867e605..0000000000 --- a/patches/server/0656-Fix-cancelled-powdered-snow-bucket-placement.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 8 Oct 2021 13:12:58 -0700 -Subject: [PATCH] Fix cancelled powdered snow bucket placement - -Cancelling the placement of powdered snow from the powdered -snow bucket didn't revert grass that became snowy because of the -placement. - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 8c9ae9ac38def29ae4cd8944395e566e434d46d0..a100c7a53b4b1dac0a01ee65418d44297bcdb93f 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -425,7 +425,7 @@ public final class ItemStack implements DataComponentHolder { - int oldCount = this.getCount(); - ServerLevel world = (ServerLevel) context.getLevel(); - -- if (!(item instanceof BucketItem || item instanceof SolidBucketItem)) { // if not bucket -+ if (!(item instanceof BucketItem/* || item instanceof SolidBucketItem*/)) { // if not bucket // Paper - Fix cancelled powdered snow bucket placement - world.captureBlockStates = true; - // special case bonemeal - if (item == Items.BONE_MEAL) { -@@ -488,7 +488,7 @@ public final class ItemStack implements DataComponentHolder { - world.capturedBlockStates.clear(); - if (blocks.size() > 1) { - placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, enumhand, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ()); -- } else if (blocks.size() == 1) { -+ } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement - placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, enumhand, blocks.get(0), blockposition.getX(), blockposition.getY(), blockposition.getZ()); - } - diff --git a/patches/server/0657-Add-GameEvent-tags.patch b/patches/server/0657-Add-GameEvent-tags.patch new file mode 100644 index 0000000000..0f1b9f52d2 --- /dev/null +++ b/patches/server/0657-Add-GameEvent-tags.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 3 Jan 2021 20:03:35 -0800 +Subject: [PATCH] Add GameEvent tags + + +diff --git a/src/main/java/io/papermc/paper/CraftGameEventTag.java b/src/main/java/io/papermc/paper/CraftGameEventTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..874c420e60b6be09c806d64f40cf63663ffddc07 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/CraftGameEventTag.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper; ++ ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.tags.TagKey; ++import org.bukkit.GameEvent; ++import org.bukkit.craftbukkit.tag.CraftTag; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Collections; ++import java.util.IdentityHashMap; ++import java.util.Map; ++import java.util.Objects; ++import java.util.Set; ++import java.util.stream.Collectors; ++ ++public class CraftGameEventTag extends CraftTag { ++ ++ public CraftGameEventTag(net.minecraft.core.Registry registry, TagKey tag) { ++ super(registry, tag); ++ } ++ ++ private static final Map> KEY_CACHE = Collections.synchronizedMap(new IdentityHashMap<>()); ++ @Override ++ public boolean isTagged(@NotNull GameEvent gameEvent) { ++ return registry.getOrThrow(KEY_CACHE.computeIfAbsent(gameEvent, event -> ResourceKey.create(Registries.GAME_EVENT, CraftNamespacedKey.toMinecraft(event.getKey())))).is(tag); ++ } ++ ++ @Override ++ public @NotNull Set getValues() { ++ return getHandle().stream().map((nms) -> Objects.requireNonNull(GameEvent.getByKey(CraftNamespacedKey.fromMinecraft(BuiltInRegistries.GAME_EVENT.getKey(nms.value()))), nms + " is not a recognized game event")).collect(Collectors.toUnmodifiableSet()); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index c1bdefbad35fd259e3d90c6e330da14c9d072090..59690263f1cb27f2289b027ffd31c1e1ac4f2e69 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2699,6 +2699,15 @@ public final class CraftServer implements Server { + return (org.bukkit.Tag) new CraftDamageTag(damageRegistry, damageTagKey); + } + } ++ // Paper start ++ case org.bukkit.Tag.REGISTRY_GAME_EVENTS -> { ++ Preconditions.checkArgument(clazz == org.bukkit.GameEvent.class, "Game Event namespace must have GameEvent type"); ++ TagKey gameEventTagKey = TagKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, key); ++ if (net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(gameEventTagKey).isPresent()) { ++ return (org.bukkit.Tag) new io.papermc.paper.CraftGameEventTag(net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT, gameEventTagKey); ++ } ++ } ++ // Paper end + default -> throw new IllegalArgumentException(); + } + +@@ -2736,6 +2745,13 @@ public final class CraftServer implements Server { + net.minecraft.core.Registry damageTags = CraftRegistry.getMinecraftRegistry(Registries.DAMAGE_TYPE); + return damageTags.getTags().map(pair -> (org.bukkit.Tag) new CraftDamageTag(damageTags, pair.key())).collect(ImmutableList.toImmutableList()); + } ++ // Paper start ++ case org.bukkit.Tag.REGISTRY_GAME_EVENTS -> { ++ Preconditions.checkArgument(clazz == org.bukkit.GameEvent.class); ++ net.minecraft.core.Registry gameEvents = net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT; ++ return gameEvents.getTags().map(pair -> (org.bukkit.Tag) new io.papermc.paper.CraftGameEventTag(gameEvents, pair.key())).collect(ImmutableList.toImmutableList()); ++ } ++ // Paper end + default -> throw new IllegalArgumentException(); + } + } diff --git a/patches/server/0657-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch b/patches/server/0657-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch deleted file mode 100644 index f3ca4340b0..0000000000 --- a/patches/server/0657-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 12 Feb 2022 12:40:50 -0700 -Subject: [PATCH] Add missing Validate calls to CraftServer#getSpawnLimit - -Copies appropriate checks from CraftWorld#getSpawnLimit - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 93811e7770546c202085487642699e0c74b9f498..8d9816f84e551f1257972f467352e9c9ee09473e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2343,6 +2343,8 @@ public final class CraftServer implements Server { - @Override - public int getSpawnLimit(SpawnCategory spawnCategory) { - // Paper start - Add mobcaps commands -+ Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); -+ Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory." + spawnCategory + " does not have a spawn limit."); - return this.getSpawnLimitUnsafe(spawnCategory); - } - public int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) { diff --git a/patches/server/0658-Add-GameEvent-tags.patch b/patches/server/0658-Add-GameEvent-tags.patch deleted file mode 100644 index 34a9b8a43e..0000000000 --- a/patches/server/0658-Add-GameEvent-tags.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 3 Jan 2021 20:03:35 -0800 -Subject: [PATCH] Add GameEvent tags - - -diff --git a/src/main/java/io/papermc/paper/CraftGameEventTag.java b/src/main/java/io/papermc/paper/CraftGameEventTag.java -new file mode 100644 -index 0000000000000000000000000000000000000000..874c420e60b6be09c806d64f40cf63663ffddc07 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/CraftGameEventTag.java -@@ -0,0 +1,35 @@ -+package io.papermc.paper; -+ -+import net.minecraft.core.registries.BuiltInRegistries; -+import net.minecraft.core.registries.Registries; -+import net.minecraft.resources.ResourceKey; -+import net.minecraft.tags.TagKey; -+import org.bukkit.GameEvent; -+import org.bukkit.craftbukkit.tag.CraftTag; -+import org.bukkit.craftbukkit.util.CraftNamespacedKey; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Collections; -+import java.util.IdentityHashMap; -+import java.util.Map; -+import java.util.Objects; -+import java.util.Set; -+import java.util.stream.Collectors; -+ -+public class CraftGameEventTag extends CraftTag { -+ -+ public CraftGameEventTag(net.minecraft.core.Registry registry, TagKey tag) { -+ super(registry, tag); -+ } -+ -+ private static final Map> KEY_CACHE = Collections.synchronizedMap(new IdentityHashMap<>()); -+ @Override -+ public boolean isTagged(@NotNull GameEvent gameEvent) { -+ return registry.getOrThrow(KEY_CACHE.computeIfAbsent(gameEvent, event -> ResourceKey.create(Registries.GAME_EVENT, CraftNamespacedKey.toMinecraft(event.getKey())))).is(tag); -+ } -+ -+ @Override -+ public @NotNull Set getValues() { -+ return getHandle().stream().map((nms) -> Objects.requireNonNull(GameEvent.getByKey(CraftNamespacedKey.fromMinecraft(BuiltInRegistries.GAME_EVENT.getKey(nms.value()))), nms + " is not a recognized game event")).collect(Collectors.toUnmodifiableSet()); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 8d9816f84e551f1257972f467352e9c9ee09473e..db6b4ec0cfbda7a65cebaa50d16f038916886475 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2700,6 +2700,15 @@ public final class CraftServer implements Server { - return (org.bukkit.Tag) new CraftDamageTag(damageRegistry, damageTagKey); - } - } -+ // Paper start -+ case org.bukkit.Tag.REGISTRY_GAME_EVENTS -> { -+ Preconditions.checkArgument(clazz == org.bukkit.GameEvent.class, "Game Event namespace must have GameEvent type"); -+ TagKey gameEventTagKey = TagKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, key); -+ if (net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(gameEventTagKey).isPresent()) { -+ return (org.bukkit.Tag) new io.papermc.paper.CraftGameEventTag(net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT, gameEventTagKey); -+ } -+ } -+ // Paper end - default -> throw new IllegalArgumentException(); - } - -@@ -2737,6 +2746,13 @@ public final class CraftServer implements Server { - net.minecraft.core.Registry damageTags = CraftRegistry.getMinecraftRegistry(Registries.DAMAGE_TYPE); - return damageTags.getTags().map(pair -> (org.bukkit.Tag) new CraftDamageTag(damageTags, pair.key())).collect(ImmutableList.toImmutableList()); - } -+ // Paper start -+ case org.bukkit.Tag.REGISTRY_GAME_EVENTS -> { -+ Preconditions.checkArgument(clazz == org.bukkit.GameEvent.class); -+ net.minecraft.core.Registry gameEvents = net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT; -+ return gameEvents.getTags().map(pair -> (org.bukkit.Tag) new io.papermc.paper.CraftGameEventTag(gameEvents, pair.key())).collect(ImmutableList.toImmutableList()); -+ } -+ // Paper end - default -> throw new IllegalArgumentException(); - } - } diff --git a/patches/server/0658-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch b/patches/server/0658-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch new file mode 100644 index 0000000000..7d399f3858 --- /dev/null +++ b/patches/server/0658-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Tue, 28 Dec 2021 07:19:01 -0800 +Subject: [PATCH] Execute chunk tasks fairly for worlds while waiting for next + tick + +Currently, only the first world would have had tasks executed. +This might result in chunks loading far slower in the nether, +for example. + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 8cbc8eeaa8719f8bb136543e80ec85248c90e154..3cd23d329fae0a6a4eff36510edc5d9bd27c804e 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1405,6 +1405,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Tue, 28 Dec 2021 07:19:01 -0800 -Subject: [PATCH] Execute chunk tasks fairly for worlds while waiting for next - tick - -Currently, only the first world would have had tasks executed. -This might result in chunks loading far slower in the nether, -for example. - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ac9b2eb3fadc2aa6f740a53b13029aa65724a37a..ff75c95f13b18171064f521f7c3b4367d9a5b9b8 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1419,6 +1419,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Thu, 13 Jan 2022 15:20:47 -0800 +Subject: [PATCH] Furnace RecipesUsed API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java +index 7b5f35779ac63b5f9b3a88cc4dcde38147fea2b7..e8d57a9497d545a84955eb3d0240844ae8276c08 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java +@@ -103,5 +103,37 @@ public abstract class CraftFurnace extends + snapshot.cookSpeedMultiplier = multiplier; + snapshot.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.isPlaced() ? this.world.getHandle() : null, snapshot, snapshot.recipeType, snapshot.cookSpeedMultiplier); // Update the snapshot's current total cook time to scale with the newly set multiplier + } ++ ++ @Override ++ public int getRecipeUsedCount(org.bukkit.NamespacedKey furnaceRecipe) { ++ return this.getSnapshot().recipesUsed.getInt(io.papermc.paper.util.MCUtil.toResourceKey(net.minecraft.core.registries.Registries.RECIPE, furnaceRecipe)); ++ } ++ ++ @Override ++ public boolean hasRecipeUsedCount(org.bukkit.NamespacedKey furnaceRecipe) { ++ return this.getSnapshot().recipesUsed.containsKey(io.papermc.paper.util.MCUtil.toResourceKey(net.minecraft.core.registries.Registries.RECIPE, furnaceRecipe)); ++ } ++ ++ @Override ++ public void setRecipeUsedCount(org.bukkit.inventory.CookingRecipe furnaceRecipe, int count) { ++ final var location = io.papermc.paper.util.MCUtil.toResourceKey(net.minecraft.core.registries.Registries.RECIPE, furnaceRecipe.getKey()); ++ java.util.Optional> nmsRecipe = (this.isPlaced() ? this.world.getHandle().recipeAccess() : net.minecraft.server.MinecraftServer.getServer().getRecipeManager()).byKey(location); ++ com.google.common.base.Preconditions.checkArgument(nmsRecipe.isPresent() && nmsRecipe.get().value() instanceof net.minecraft.world.item.crafting.AbstractCookingRecipe, furnaceRecipe.getKey() + " is not recognized as a valid and registered furnace recipe"); ++ if (count > 0) { ++ this.getSnapshot().recipesUsed.put(location, count); ++ } else { ++ this.getSnapshot().recipesUsed.removeInt(location); ++ } ++ } ++ ++ @Override ++ public void setRecipesUsed(java.util.Map, Integer> recipesUsed) { ++ this.getSnapshot().recipesUsed.clear(); ++ recipesUsed.forEach((recipe, integer) -> { ++ if (integer != null) { ++ this.setRecipeUsedCount(recipe, integer); ++ } ++ }); ++ } + // Paper end + } diff --git a/patches/server/0660-Configurable-sculk-sensor-listener-range.patch b/patches/server/0660-Configurable-sculk-sensor-listener-range.patch new file mode 100644 index 0000000000..3dd1324354 --- /dev/null +++ b/patches/server/0660-Configurable-sculk-sensor-listener-range.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 19 Aug 2021 18:45:42 -0700 +Subject: [PATCH] Configurable sculk sensor listener range + +== AT == +public-f net.minecraft.world.level.gameevent.vibrations.VibrationListener listenerRange + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java +index 41ccbee5fc7767a7d5e1cdca0ec7d9a17ee80a90..1d28f117965da22694b12018923a5f1347905085 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java +@@ -20,6 +20,12 @@ public class CalibratedSculkSensorBlockEntity extends SculkSensorBlockEntity { + public VibrationSystem.User createVibrationUser() { + return new CalibratedSculkSensorBlockEntity.VibrationUser(this.getBlockPos()); + } ++ // Paper start - Configurable sculk sensor listener range ++ @Override ++ protected void saveRangeOverride(final net.minecraft.nbt.CompoundTag nbt) { ++ if (this.rangeOverride != null && this.rangeOverride != 16) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default ++ } ++ // Paper end - Configurable sculk sensor listener range + + protected class VibrationUser extends SculkSensorBlockEntity.VibrationUser { + public VibrationUser(final BlockPos pos) { +@@ -28,6 +34,7 @@ public class CalibratedSculkSensorBlockEntity extends SculkSensorBlockEntity { + + @Override + public int getListenerRadius() { ++ if (CalibratedSculkSensorBlockEntity.this.rangeOverride != null) return CalibratedSculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range + return 16; + } + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java +index 070814eb011ab8e02218c91e1cf75be5501c1a0a..28849cf84afcdc0d9fc245fac1a8d769a2db3b68 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java +@@ -26,6 +26,7 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList + private final VibrationSystem.Listener vibrationListener; + private final VibrationSystem.User vibrationUser = this.createVibrationUser(); + public int lastVibrationFrequency; ++ @Nullable public Integer rangeOverride = null; // Paper - Configurable sculk sensor listener range + + protected SculkSensorBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); +@@ -52,8 +53,16 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList + .resultOrPartial(string -> LOGGER.error("Failed to parse vibration listener for Sculk Sensor: '{}'", string)) + .ifPresent(listener -> this.vibrationData = listener); + } ++ // Paper start - Configurable sculk sensor listener range ++ if (nbt.contains(PAPER_LISTENER_RANGE_NBT_KEY)) { ++ this.rangeOverride = nbt.getInt(PAPER_LISTENER_RANGE_NBT_KEY); ++ } else { ++ this.rangeOverride = null; ++ } ++ // Paper end - Configurable sculk sensor listener range + } + ++ protected static final String PAPER_LISTENER_RANGE_NBT_KEY = "Paper.ListenerRange"; // Paper - Configurable sculk sensor listener range + @Override + protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.saveAdditional(nbt, registries); +@@ -63,7 +72,13 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList + .encodeStart(registryOps, this.vibrationData) + .resultOrPartial(string -> LOGGER.error("Failed to encode vibration listener for Sculk Sensor: '{}'", string)) + .ifPresent(listenerNbt -> nbt.put("listener", listenerNbt)); ++ this.saveRangeOverride(nbt); // Paper - Configurable sculk sensor listener range ++ } ++ // Paper start - Configurable sculk sensor listener range ++ protected void saveRangeOverride(CompoundTag nbt) { ++ if (this.rangeOverride != null && this.rangeOverride != VibrationUser.LISTENER_RANGE) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default + } ++ // Paper end - Configurable sculk sensor listener range + + @Override + public VibrationSystem.Data getVibrationData() { +@@ -100,6 +115,7 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList + + @Override + public int getListenerRadius() { ++ if (SculkSensorBlockEntity.this.rangeOverride != null) return SculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range + return 8; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java +index 70d85dbfcaae7ee632a4f541334302b46615a254..6ba229afb0219ff229fd794c59d7585f010742ee 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java +@@ -36,4 +36,17 @@ public class CraftSculkSensor extends CraftBlo + public CraftSculkSensor copy(Location location) { + return new CraftSculkSensor<>(this, location); + } ++ ++ // Paper start ++ @Override ++ public int getListenerRange() { ++ return this.getSnapshot().getListener().getListenerRadius(); ++ } ++ ++ @Override ++ public void setListenerRange(int range) { ++ Preconditions.checkArgument(range > 0, "Vibration listener range must be greater than 0"); ++ this.getSnapshot().rangeOverride = range; ++ } ++ // Paper end + } diff --git a/patches/server/0660-Furnace-RecipesUsed-API.patch b/patches/server/0660-Furnace-RecipesUsed-API.patch deleted file mode 100644 index 5b19cd68c0..0000000000 --- a/patches/server/0660-Furnace-RecipesUsed-API.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 13 Jan 2022 15:20:47 -0800 -Subject: [PATCH] Furnace RecipesUsed API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java -index 7b5f35779ac63b5f9b3a88cc4dcde38147fea2b7..e8d57a9497d545a84955eb3d0240844ae8276c08 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java -@@ -103,5 +103,37 @@ public abstract class CraftFurnace extends - snapshot.cookSpeedMultiplier = multiplier; - snapshot.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.isPlaced() ? this.world.getHandle() : null, snapshot, snapshot.recipeType, snapshot.cookSpeedMultiplier); // Update the snapshot's current total cook time to scale with the newly set multiplier - } -+ -+ @Override -+ public int getRecipeUsedCount(org.bukkit.NamespacedKey furnaceRecipe) { -+ return this.getSnapshot().recipesUsed.getInt(io.papermc.paper.util.MCUtil.toResourceKey(net.minecraft.core.registries.Registries.RECIPE, furnaceRecipe)); -+ } -+ -+ @Override -+ public boolean hasRecipeUsedCount(org.bukkit.NamespacedKey furnaceRecipe) { -+ return this.getSnapshot().recipesUsed.containsKey(io.papermc.paper.util.MCUtil.toResourceKey(net.minecraft.core.registries.Registries.RECIPE, furnaceRecipe)); -+ } -+ -+ @Override -+ public void setRecipeUsedCount(org.bukkit.inventory.CookingRecipe furnaceRecipe, int count) { -+ final var location = io.papermc.paper.util.MCUtil.toResourceKey(net.minecraft.core.registries.Registries.RECIPE, furnaceRecipe.getKey()); -+ java.util.Optional> nmsRecipe = (this.isPlaced() ? this.world.getHandle().recipeAccess() : net.minecraft.server.MinecraftServer.getServer().getRecipeManager()).byKey(location); -+ com.google.common.base.Preconditions.checkArgument(nmsRecipe.isPresent() && nmsRecipe.get().value() instanceof net.minecraft.world.item.crafting.AbstractCookingRecipe, furnaceRecipe.getKey() + " is not recognized as a valid and registered furnace recipe"); -+ if (count > 0) { -+ this.getSnapshot().recipesUsed.put(location, count); -+ } else { -+ this.getSnapshot().recipesUsed.removeInt(location); -+ } -+ } -+ -+ @Override -+ public void setRecipesUsed(java.util.Map, Integer> recipesUsed) { -+ this.getSnapshot().recipesUsed.clear(); -+ recipesUsed.forEach((recipe, integer) -> { -+ if (integer != null) { -+ this.setRecipeUsedCount(recipe, integer); -+ } -+ }); -+ } - // Paper end - } diff --git a/patches/server/0661-Add-missing-block-data-API.patch b/patches/server/0661-Add-missing-block-data-API.patch new file mode 100644 index 0000000000..ace8c632a6 --- /dev/null +++ b/patches/server/0661-Add-missing-block-data-API.patch @@ -0,0 +1,214 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Oct 2021 22:57:31 -0700 +Subject: [PATCH] Add missing block data API + +General purpose patch adding missing getters/setters to BlockData and +its child types. + +Co-authored-by: SoSeDiK +Co-authored-by: Fabrizio La Rosa + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java +index 2ccf3fbe3f991b7a014cff3bcd424e6a81bc310a..e5450d3511389bf3bd6461fb6ec65ea82e4ae9f0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java +@@ -51,4 +51,11 @@ public final class CraftBed extends org.bukkit.craftbukkit.block.data.CraftBlock + public java.util.Set getFaces() { + return this.getValues(CraftBed.FACING, org.bukkit.block.BlockFace.class); + } ++ ++ // Paper start ++ @Override ++ public void setOccupied(boolean occupied) { ++ set(CraftBed.OCCUPIED, occupied); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java +index 2230160d5e04e979467a56346600436c1e5dd70c..08436bfeba2f35fb11b16c4f71f76e13c0d44b1a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java +@@ -31,6 +31,12 @@ public final class CraftCandle extends org.bukkit.craftbukkit.block.data.CraftBl + public int getMaximumCandles() { + return getMax(CraftCandle.CANDLES); + } ++ // Paper start ++ @Override ++ public int getMinimumCandles() { ++ return getMin(CraftCandle.CANDLES); ++ } ++ // Paper end + + // org.bukkit.craftbukkit.block.data.CraftLightable + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java +index af29ff861eb2c504ef31cc3236adf1e7f6b46049..bc32c5d4c7568ed4392e4bdb5872066846aa62b6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java +@@ -51,4 +51,16 @@ public final class CraftCherryLeaves extends org.bukkit.craftbukkit.block.data.C + public void setWaterlogged(boolean waterlogged) { + this.set(CraftCherryLeaves.WATERLOGGED, waterlogged); + } ++ ++ // Paper start ++ @Override ++ public int getMaximumDistance() { ++ return getMax(DISTANCE); ++ } ++ ++ @Override ++ public int getMinimumDistance() { ++ return getMin(DISTANCE); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java +index 7ce2e8b733bcd496dcfccb1ddfcb7c5c1b64052e..5ae27fc8f9d18bae949d335ea53e7e70917f0e80 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java +@@ -31,4 +31,11 @@ public final class CraftComposter extends org.bukkit.craftbukkit.block.data.Craf + public int getMaximumLevel() { + return getMax(CraftComposter.LEVEL); + } ++ ++ // Paper start ++ @Override ++ public int getMinimumLevel() { ++ return getMin(CraftComposter.LEVEL); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java +index 356230b9b266974e36d0508f8c239714d673504d..b7ea9a6fba6b4fc157dfcc4bee099871b8ad7380 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java +@@ -45,4 +45,18 @@ public final class CraftDecoratedPot extends org.bukkit.craftbukkit.block.data.C + public void setWaterlogged(boolean waterlogged) { + this.set(CraftDecoratedPot.WATERLOGGED, waterlogged); + } ++ ++ // Paper start - add missing block data api ++ private static final net.minecraft.world.level.block.state.properties.BooleanProperty CRACKED = getBoolean(net.minecraft.world.level.block.DecoratedPotBlock.class, "cracked"); ++ ++ @Override ++ public boolean isCracked() { ++ return this.get(CraftDecoratedPot.CRACKED); ++ } ++ ++ @Override ++ public void setCracked(final boolean cracked) { ++ this.set(CraftDecoratedPot.CRACKED, cracked); ++ } ++ // Paper end - add missing block data api + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java +index 70d734fc71a4499bbf569b3908aa5fbbdf19e6a0..1af5fe48c5861077555e6bdeb6312859b7b37eb2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java +@@ -31,4 +31,11 @@ public final class CraftFluids extends org.bukkit.craftbukkit.block.data.CraftBl + public int getMaximumLevel() { + return getMax(CraftFluids.LEVEL); + } ++ ++ // Paper start ++ @Override ++ public int getMinimumLevel() { ++ return getMin(CraftFluids.LEVEL); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java +index bf0d53f65f8a672c385b2e798b109a9662725f9e..c0e0cbceb0b5c36f4ac4672f217027a5898900a6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java +@@ -31,4 +31,11 @@ public final class CraftLayeredCauldron extends org.bukkit.craftbukkit.block.dat + public int getMaximumLevel() { + return getMax(CraftLayeredCauldron.LEVEL); + } ++ ++ // Paper start ++ @Override ++ public int getMinimumLevel() { ++ return getMin(CraftLayeredCauldron.LEVEL); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java +index 33d9a950ed678595fe2573e9f89a8d1716040503..ab336b400c1937ff86b681b27b1550e4b7f1ab79 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java +@@ -51,4 +51,16 @@ public final class CraftLeaves extends org.bukkit.craftbukkit.block.data.CraftBl + public void setWaterlogged(boolean waterlogged) { + this.set(CraftLeaves.WATERLOGGED, waterlogged); + } ++ ++ // Paper start ++ @Override ++ public int getMaximumDistance() { ++ return getMax(CraftLeaves.DISTANCE); ++ } ++ ++ @Override ++ public int getMinimumDistance() { ++ return getMin(CraftLeaves.DISTANCE); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java +index 49f314b1447212a1a5a7623d2302b5960a44ce6e..8c936a95effa84ba0337d2aaf880cc561591fb33 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java +@@ -32,6 +32,13 @@ public final class CraftLight extends org.bukkit.craftbukkit.block.data.CraftBlo + return getMax(CraftLight.LEVEL); + } + ++ // Paper start ++ @Override ++ public int getMinimumLevel() { ++ return getMin(CraftLight.LEVEL); ++ } ++ // Paper end ++ + // org.bukkit.craftbukkit.block.data.CraftWaterlogged + + private static final net.minecraft.world.level.block.state.properties.BooleanProperty WATERLOGGED = getBoolean(net.minecraft.world.level.block.LightBlock.class, "waterlogged"); +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java +index 7a1f2fd2f7f8f1b46352fe2c4d0cdf23a88020fd..8b621aaeadcf2cc6e2ccdbab92f4ae2b89a6ca08 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java +@@ -51,4 +51,16 @@ public final class CraftMangroveLeaves extends org.bukkit.craftbukkit.block.data + public void setWaterlogged(boolean waterlogged) { + this.set(CraftMangroveLeaves.WATERLOGGED, waterlogged); + } ++ ++ // Paper start ++ @Override ++ public int getMinimumDistance() { ++ return getMin(CraftMangroveLeaves.DISTANCE); ++ } ++ ++ @Override ++ public int getMaximumDistance() { ++ return getMax(CraftMangroveLeaves.DISTANCE); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java +index 78b220a6f460cd91ad1574c0d32f3e4288eaf431..0f7df1b4c58ba731832958043ba345ec77737e54 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java +@@ -27,6 +27,13 @@ public final class CraftPinkPetals extends org.bukkit.craftbukkit.block.data.Cra + this.set(CraftPinkPetals.FLOWER_AMOUNT, flower_amount); + } + ++ // Paper start ++ @Override ++ public int getMinimumFlowerAmount() { ++ return getMin(CraftPinkPetals.FLOWER_AMOUNT); ++ } ++ // Paper end ++ + @Override + public int getMaximumFlowerAmount() { + return getMax(CraftPinkPetals.FLOWER_AMOUNT); diff --git a/patches/server/0661-Configurable-sculk-sensor-listener-range.patch b/patches/server/0661-Configurable-sculk-sensor-listener-range.patch deleted file mode 100644 index 3dd1324354..0000000000 --- a/patches/server/0661-Configurable-sculk-sensor-listener-range.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 19 Aug 2021 18:45:42 -0700 -Subject: [PATCH] Configurable sculk sensor listener range - -== AT == -public-f net.minecraft.world.level.gameevent.vibrations.VibrationListener listenerRange - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java -index 41ccbee5fc7767a7d5e1cdca0ec7d9a17ee80a90..1d28f117965da22694b12018923a5f1347905085 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java -@@ -20,6 +20,12 @@ public class CalibratedSculkSensorBlockEntity extends SculkSensorBlockEntity { - public VibrationSystem.User createVibrationUser() { - return new CalibratedSculkSensorBlockEntity.VibrationUser(this.getBlockPos()); - } -+ // Paper start - Configurable sculk sensor listener range -+ @Override -+ protected void saveRangeOverride(final net.minecraft.nbt.CompoundTag nbt) { -+ if (this.rangeOverride != null && this.rangeOverride != 16) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default -+ } -+ // Paper end - Configurable sculk sensor listener range - - protected class VibrationUser extends SculkSensorBlockEntity.VibrationUser { - public VibrationUser(final BlockPos pos) { -@@ -28,6 +34,7 @@ public class CalibratedSculkSensorBlockEntity extends SculkSensorBlockEntity { - - @Override - public int getListenerRadius() { -+ if (CalibratedSculkSensorBlockEntity.this.rangeOverride != null) return CalibratedSculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range - return 16; - } - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java -index 070814eb011ab8e02218c91e1cf75be5501c1a0a..28849cf84afcdc0d9fc245fac1a8d769a2db3b68 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java -@@ -26,6 +26,7 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList - private final VibrationSystem.Listener vibrationListener; - private final VibrationSystem.User vibrationUser = this.createVibrationUser(); - public int lastVibrationFrequency; -+ @Nullable public Integer rangeOverride = null; // Paper - Configurable sculk sensor listener range - - protected SculkSensorBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); -@@ -52,8 +53,16 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList - .resultOrPartial(string -> LOGGER.error("Failed to parse vibration listener for Sculk Sensor: '{}'", string)) - .ifPresent(listener -> this.vibrationData = listener); - } -+ // Paper start - Configurable sculk sensor listener range -+ if (nbt.contains(PAPER_LISTENER_RANGE_NBT_KEY)) { -+ this.rangeOverride = nbt.getInt(PAPER_LISTENER_RANGE_NBT_KEY); -+ } else { -+ this.rangeOverride = null; -+ } -+ // Paper end - Configurable sculk sensor listener range - } - -+ protected static final String PAPER_LISTENER_RANGE_NBT_KEY = "Paper.ListenerRange"; // Paper - Configurable sculk sensor listener range - @Override - protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) { - super.saveAdditional(nbt, registries); -@@ -63,7 +72,13 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList - .encodeStart(registryOps, this.vibrationData) - .resultOrPartial(string -> LOGGER.error("Failed to encode vibration listener for Sculk Sensor: '{}'", string)) - .ifPresent(listenerNbt -> nbt.put("listener", listenerNbt)); -+ this.saveRangeOverride(nbt); // Paper - Configurable sculk sensor listener range -+ } -+ // Paper start - Configurable sculk sensor listener range -+ protected void saveRangeOverride(CompoundTag nbt) { -+ if (this.rangeOverride != null && this.rangeOverride != VibrationUser.LISTENER_RANGE) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default - } -+ // Paper end - Configurable sculk sensor listener range - - @Override - public VibrationSystem.Data getVibrationData() { -@@ -100,6 +115,7 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList - - @Override - public int getListenerRadius() { -+ if (SculkSensorBlockEntity.this.rangeOverride != null) return SculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range - return 8; - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java -index 70d85dbfcaae7ee632a4f541334302b46615a254..6ba229afb0219ff229fd794c59d7585f010742ee 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java -@@ -36,4 +36,17 @@ public class CraftSculkSensor extends CraftBlo - public CraftSculkSensor copy(Location location) { - return new CraftSculkSensor<>(this, location); - } -+ -+ // Paper start -+ @Override -+ public int getListenerRange() { -+ return this.getSnapshot().getListener().getListenerRadius(); -+ } -+ -+ @Override -+ public void setListenerRange(int range) { -+ Preconditions.checkArgument(range > 0, "Vibration listener range must be greater than 0"); -+ this.getSnapshot().rangeOverride = range; -+ } -+ // Paper end - } diff --git a/patches/server/0662-Add-missing-block-data-API.patch b/patches/server/0662-Add-missing-block-data-API.patch deleted file mode 100644 index ace8c632a6..0000000000 --- a/patches/server/0662-Add-missing-block-data-API.patch +++ /dev/null @@ -1,214 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 16 Oct 2021 22:57:31 -0700 -Subject: [PATCH] Add missing block data API - -General purpose patch adding missing getters/setters to BlockData and -its child types. - -Co-authored-by: SoSeDiK -Co-authored-by: Fabrizio La Rosa - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java -index 2ccf3fbe3f991b7a014cff3bcd424e6a81bc310a..e5450d3511389bf3bd6461fb6ec65ea82e4ae9f0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java -@@ -51,4 +51,11 @@ public final class CraftBed extends org.bukkit.craftbukkit.block.data.CraftBlock - public java.util.Set getFaces() { - return this.getValues(CraftBed.FACING, org.bukkit.block.BlockFace.class); - } -+ -+ // Paper start -+ @Override -+ public void setOccupied(boolean occupied) { -+ set(CraftBed.OCCUPIED, occupied); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java -index 2230160d5e04e979467a56346600436c1e5dd70c..08436bfeba2f35fb11b16c4f71f76e13c0d44b1a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java -@@ -31,6 +31,12 @@ public final class CraftCandle extends org.bukkit.craftbukkit.block.data.CraftBl - public int getMaximumCandles() { - return getMax(CraftCandle.CANDLES); - } -+ // Paper start -+ @Override -+ public int getMinimumCandles() { -+ return getMin(CraftCandle.CANDLES); -+ } -+ // Paper end - - // org.bukkit.craftbukkit.block.data.CraftLightable - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java -index af29ff861eb2c504ef31cc3236adf1e7f6b46049..bc32c5d4c7568ed4392e4bdb5872066846aa62b6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java -@@ -51,4 +51,16 @@ public final class CraftCherryLeaves extends org.bukkit.craftbukkit.block.data.C - public void setWaterlogged(boolean waterlogged) { - this.set(CraftCherryLeaves.WATERLOGGED, waterlogged); - } -+ -+ // Paper start -+ @Override -+ public int getMaximumDistance() { -+ return getMax(DISTANCE); -+ } -+ -+ @Override -+ public int getMinimumDistance() { -+ return getMin(DISTANCE); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java -index 7ce2e8b733bcd496dcfccb1ddfcb7c5c1b64052e..5ae27fc8f9d18bae949d335ea53e7e70917f0e80 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java -@@ -31,4 +31,11 @@ public final class CraftComposter extends org.bukkit.craftbukkit.block.data.Craf - public int getMaximumLevel() { - return getMax(CraftComposter.LEVEL); - } -+ -+ // Paper start -+ @Override -+ public int getMinimumLevel() { -+ return getMin(CraftComposter.LEVEL); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java -index 356230b9b266974e36d0508f8c239714d673504d..b7ea9a6fba6b4fc157dfcc4bee099871b8ad7380 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java -@@ -45,4 +45,18 @@ public final class CraftDecoratedPot extends org.bukkit.craftbukkit.block.data.C - public void setWaterlogged(boolean waterlogged) { - this.set(CraftDecoratedPot.WATERLOGGED, waterlogged); - } -+ -+ // Paper start - add missing block data api -+ private static final net.minecraft.world.level.block.state.properties.BooleanProperty CRACKED = getBoolean(net.minecraft.world.level.block.DecoratedPotBlock.class, "cracked"); -+ -+ @Override -+ public boolean isCracked() { -+ return this.get(CraftDecoratedPot.CRACKED); -+ } -+ -+ @Override -+ public void setCracked(final boolean cracked) { -+ this.set(CraftDecoratedPot.CRACKED, cracked); -+ } -+ // Paper end - add missing block data api - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java -index 70d734fc71a4499bbf569b3908aa5fbbdf19e6a0..1af5fe48c5861077555e6bdeb6312859b7b37eb2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java -@@ -31,4 +31,11 @@ public final class CraftFluids extends org.bukkit.craftbukkit.block.data.CraftBl - public int getMaximumLevel() { - return getMax(CraftFluids.LEVEL); - } -+ -+ // Paper start -+ @Override -+ public int getMinimumLevel() { -+ return getMin(CraftFluids.LEVEL); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java -index bf0d53f65f8a672c385b2e798b109a9662725f9e..c0e0cbceb0b5c36f4ac4672f217027a5898900a6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java -@@ -31,4 +31,11 @@ public final class CraftLayeredCauldron extends org.bukkit.craftbukkit.block.dat - public int getMaximumLevel() { - return getMax(CraftLayeredCauldron.LEVEL); - } -+ -+ // Paper start -+ @Override -+ public int getMinimumLevel() { -+ return getMin(CraftLayeredCauldron.LEVEL); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java -index 33d9a950ed678595fe2573e9f89a8d1716040503..ab336b400c1937ff86b681b27b1550e4b7f1ab79 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java -@@ -51,4 +51,16 @@ public final class CraftLeaves extends org.bukkit.craftbukkit.block.data.CraftBl - public void setWaterlogged(boolean waterlogged) { - this.set(CraftLeaves.WATERLOGGED, waterlogged); - } -+ -+ // Paper start -+ @Override -+ public int getMaximumDistance() { -+ return getMax(CraftLeaves.DISTANCE); -+ } -+ -+ @Override -+ public int getMinimumDistance() { -+ return getMin(CraftLeaves.DISTANCE); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java -index 49f314b1447212a1a5a7623d2302b5960a44ce6e..8c936a95effa84ba0337d2aaf880cc561591fb33 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java -@@ -32,6 +32,13 @@ public final class CraftLight extends org.bukkit.craftbukkit.block.data.CraftBlo - return getMax(CraftLight.LEVEL); - } - -+ // Paper start -+ @Override -+ public int getMinimumLevel() { -+ return getMin(CraftLight.LEVEL); -+ } -+ // Paper end -+ - // org.bukkit.craftbukkit.block.data.CraftWaterlogged - - private static final net.minecraft.world.level.block.state.properties.BooleanProperty WATERLOGGED = getBoolean(net.minecraft.world.level.block.LightBlock.class, "waterlogged"); -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java -index 7a1f2fd2f7f8f1b46352fe2c4d0cdf23a88020fd..8b621aaeadcf2cc6e2ccdbab92f4ae2b89a6ca08 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java -@@ -51,4 +51,16 @@ public final class CraftMangroveLeaves extends org.bukkit.craftbukkit.block.data - public void setWaterlogged(boolean waterlogged) { - this.set(CraftMangroveLeaves.WATERLOGGED, waterlogged); - } -+ -+ // Paper start -+ @Override -+ public int getMinimumDistance() { -+ return getMin(CraftMangroveLeaves.DISTANCE); -+ } -+ -+ @Override -+ public int getMaximumDistance() { -+ return getMax(CraftMangroveLeaves.DISTANCE); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java -index 78b220a6f460cd91ad1574c0d32f3e4288eaf431..0f7df1b4c58ba731832958043ba345ec77737e54 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java -@@ -27,6 +27,13 @@ public final class CraftPinkPetals extends org.bukkit.craftbukkit.block.data.Cra - this.set(CraftPinkPetals.FLOWER_AMOUNT, flower_amount); - } - -+ // Paper start -+ @Override -+ public int getMinimumFlowerAmount() { -+ return getMin(CraftPinkPetals.FLOWER_AMOUNT); -+ } -+ // Paper end -+ - @Override - public int getMaximumFlowerAmount() { - return getMax(CraftPinkPetals.FLOWER_AMOUNT); diff --git a/patches/server/0662-Option-to-have-default-CustomSpawners-in-custom-worl.patch b/patches/server/0662-Option-to-have-default-CustomSpawners-in-custom-worl.patch new file mode 100644 index 0000000000..622b090c3c --- /dev/null +++ b/patches/server/0662-Option-to-have-default-CustomSpawners-in-custom-worl.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 19 Feb 2022 20:15:41 -0800 +Subject: [PATCH] Option to have default CustomSpawners in custom worlds + +By default, only LevelStem's that specifically match the ResourceKey for +OVERWORLD will have the 5 (currently) impls of CustomSpawner (for +phantoms, wandering traders, etc.). This adds an option to instead of +just looking at the LevelStem key, look at the DimensionType key which +is one level below that. Defaults to off to keep vanilla behavior. + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 3cd23d329fae0a6a4eff36510edc5d9bd27c804e..6fdc5be323833c4ca2722b695fe790ea2ecc53d5 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -646,7 +646,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop spawners; ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useDimensionTypeForCustomSpawners && this.registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE).getResourceKey(worlddimension.type().value()).orElseThrow() == net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD) { ++ spawners = list; ++ } else { ++ spawners = Collections.emptyList(); ++ } ++ world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, spawners, true, this.overworld().getRandomSequences(), org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider); ++ // Paper end - option to use the dimension_type to check if spawners should be added + } + + worlddata.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified()); diff --git a/patches/server/0663-Option-to-have-default-CustomSpawners-in-custom-worl.patch b/patches/server/0663-Option-to-have-default-CustomSpawners-in-custom-worl.patch deleted file mode 100644 index 0ee3311bc7..0000000000 --- a/patches/server/0663-Option-to-have-default-CustomSpawners-in-custom-worl.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 19 Feb 2022 20:15:41 -0800 -Subject: [PATCH] Option to have default CustomSpawners in custom worlds - -By default, only LevelStem's that specifically match the ResourceKey for -OVERWORLD will have the 5 (currently) impls of CustomSpawner (for -phantoms, wandering traders, etc.). This adds an option to instead of -just looking at the LevelStem key, look at the DimensionType key which -is one level below that. Defaults to off to keep vanilla behavior. - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ff75c95f13b18171064f521f7c3b4367d9a5b9b8..c5ee4c255ae7a1f0dc662f0d375607935e5e097a 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -647,7 +647,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop spawners; -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useDimensionTypeForCustomSpawners && this.registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE).getResourceKey(worlddimension.type().value()).orElseThrow() == net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD) { -+ spawners = list; -+ } else { -+ spawners = Collections.emptyList(); -+ } -+ world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, spawners, true, this.overworld().getRandomSequences(), org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider); -+ // Paper end - option to use the dimension_type to check if spawners should be added - } - - worlddata.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified()); diff --git a/patches/server/0663-Put-world-into-worldlist-before-initing-the-world.patch b/patches/server/0663-Put-world-into-worldlist-before-initing-the-world.patch new file mode 100644 index 0000000000..1820be4ba9 --- /dev/null +++ b/patches/server/0663-Put-world-into-worldlist-before-initing-the-world.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Tue, 22 Feb 2022 14:21:35 -0800 +Subject: [PATCH] Put world into worldlist before initing the world + +Some parts of legacy conversion will need the overworld +to get the legacy structure data storage + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 6fdc5be323833c4ca2722b695fe790ea2ecc53d5..88d4021bc4f9ab7c9ee33a5a5c2326b7c628f4a4 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -658,9 +658,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Thu, 7 Oct 2021 14:34:55 -0700 +Subject: [PATCH] Custom Potion Mixes + +== AT == +public-f net.minecraft.server.MinecraftServer potionBrewing + +diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java b/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d9390227a2bba4e03aa9ee592ca157127633c41b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java +@@ -0,0 +1,56 @@ ++package io.papermc.paper.potion; ++ ++import com.google.common.base.Preconditions; ++import java.util.Collection; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.NamespacedKey; ++import org.bukkit.potion.PotionBrewer; ++import org.bukkit.potion.PotionEffect; ++import org.bukkit.potion.PotionType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class PaperPotionBrewer implements PotionBrewer { ++ ++ private final MinecraftServer minecraftServer; ++ ++ public PaperPotionBrewer(final MinecraftServer minecraftServer) { ++ this.minecraftServer = minecraftServer; ++ } ++ ++ @Override ++ @Deprecated(forRemoval = true) ++ public Collection getEffects(PotionType type, boolean upgraded, boolean extended) { ++ final org.bukkit.NamespacedKey key = type.getKey(); ++ ++ Preconditions.checkArgument(!key.getKey().startsWith("strong_"), "Strong potion type cannot be used directly, got %s", key); ++ Preconditions.checkArgument(!key.getKey().startsWith("long_"), "Extended potion type cannot be used directly, got %s", key); ++ ++ org.bukkit.NamespacedKey effectiveKey = key; ++ if (upgraded) { ++ effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "strong_" + key.key()); ++ } else if (extended) { ++ effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "long_" + key.key()); ++ } ++ ++ final org.bukkit.potion.PotionType effectivePotionType = org.bukkit.Registry.POTION.get(effectiveKey); ++ Preconditions.checkNotNull(type, "Unknown potion type from data " + effectiveKey.asMinimalString()); // Legacy error message in 1.20.4 ++ return effectivePotionType.getPotionEffects(); ++ } ++ ++ @Override ++ public void addPotionMix(final PotionMix potionMix) { ++ this.minecraftServer.potionBrewing().addPotionMix(potionMix); ++ } ++ ++ @Override ++ public void removePotionMix(final NamespacedKey key) { ++ this.minecraftServer.potionBrewing.removePotionMix(key); ++ } ++ ++ @Override ++ public void resetPotionMixes() { ++ this.minecraftServer.potionBrewing = this.minecraftServer.potionBrewing().reload(this.minecraftServer.getWorldData().enabledFeatures()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionMix.java b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7ea357ac2f3a93db4ebdf24b5072be7d1cad3e33 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java +@@ -0,0 +1,21 @@ ++package io.papermc.paper.potion; ++ ++import java.util.function.Predicate; ++import net.minecraft.world.item.ItemStack; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.inventory.CraftRecipe; ++import org.bukkit.inventory.RecipeChoice; ++ ++public record PaperPotionMix(ItemStack result, Predicate input, Predicate ingredient) { ++ ++ public PaperPotionMix(PotionMix potionMix) { ++ this(CraftItemStack.asNMSCopy(potionMix.getResult()), convert(potionMix.getInput()), convert(potionMix.getIngredient())); ++ } ++ ++ static Predicate convert(final RecipeChoice choice) { ++ if (choice instanceof PredicateRecipeChoice predicateRecipeChoice) { ++ return stack -> predicateRecipeChoice.test(CraftItemStack.asBukkitCopy(stack)); ++ } ++ return CraftRecipe.toIngredient(choice, true); ++ } ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 88d4021bc4f9ab7c9ee33a5a5c2326b7c628f4a4..a836ea518bc6d8ddd7c6484038d3d712b3fb13cf 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2196,6 +2196,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop containers; + private final List> potionMixes; + private final List> containerMixes; ++ private final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap customMixes = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper - Custom Potion Mixes + + PotionBrewing(List potionTypes, List> potionRecipes, List> itemRecipes) { + this.containers = potionTypes; +@@ -27,7 +28,7 @@ public class PotionBrewing { + } + + public boolean isIngredient(ItemStack stack) { +- return this.isContainerIngredient(stack) || this.isPotionIngredient(stack); ++ return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || this.isCustomIngredient(stack); // Paper - Custom Potion Mixes + } + + private boolean isContainer(ItemStack stack) { +@@ -71,6 +72,11 @@ public class PotionBrewing { + } + + public boolean hasMix(ItemStack input, ItemStack ingredient) { ++ // Paper start - Custom Potion Mixes ++ if (this.hasCustomMix(input, ingredient)) { ++ return true; ++ } ++ // Paper end - Custom Potion Mixes + return this.isContainer(input) && (this.hasContainerMix(input, ingredient) || this.hasPotionMix(input, ingredient)); + } + +@@ -103,6 +109,13 @@ public class PotionBrewing { + if (input.isEmpty()) { + return input; + } else { ++ // Paper start - Custom Potion Mixes ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(input) && mix.ingredient().test(ingredient)) { ++ return mix.result().copy(); ++ } ++ } ++ // Paper end - Custom Potion Mixes + Optional> optional = input.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion(); + if (optional.isEmpty()) { + return input; +@@ -190,6 +203,50 @@ public class PotionBrewing { + builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING); + } + ++ // Paper start - Custom Potion Mixes ++ public boolean isCustomIngredient(ItemStack stack) { ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.ingredient().test(stack)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ public boolean isCustomInput(ItemStack stack) { ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(stack)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ private boolean hasCustomMix(ItemStack input, ItemStack ingredient) { ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(input) && mix.ingredient().test(ingredient)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ public void addPotionMix(io.papermc.paper.potion.PotionMix mix) { ++ if (this.customMixes.containsKey(mix.getKey())) { ++ throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey()); ++ } ++ this.customMixes.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix)); ++ } ++ ++ public boolean removePotionMix(org.bukkit.NamespacedKey key) { ++ return this.customMixes.remove(key) != null; ++ } ++ ++ public PotionBrewing reload(FeatureFlagSet flags) { ++ return bootstrap(flags); ++ } ++ // Paper end - Custom Potion Mixes ++ + public static class Builder { + private final List containers = new ArrayList<>(); + private final List> potionMixes = new ArrayList<>(); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java +index e167c2834f1b7899a7d11cef782940deeb739a9c..2bafacd7bc56186d9105d2031180f8c4a6940018 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java +@@ -316,12 +316,12 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements + + @Override + public boolean canPlaceItem(int slot, ItemStack stack) { ++ PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; // Paper - move up + if (slot == 3) { +- PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; + + return potionbrewer.isIngredient(stack); + } else { +- return slot == 4 ? stack.is(ItemTags.BREWING_FUEL) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE)) && this.getItem(slot).isEmpty(); ++ return slot == 4 ? stack.is(ItemTags.BREWING_FUEL) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionbrewer.isCustomInput(stack)) && this.getItem(slot).isEmpty(); // Paper - Custom Potion Mixes + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index fcd8b3ce258bdb12a87d41d348ac847d5dc603f8..3b48a8107bf0b4326b86ee08bb54341825be81c1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -311,6 +311,7 @@ public final class CraftServer implements Server { + private final io.papermc.paper.datapack.PaperDatapackManager datapackManager; // Paper + public static Exception excessiveVelEx; // Paper - Velocity warnings + private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher(); // Paper ++ private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer; // Paper - Custom Potion Mixes + + static { + ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); +@@ -394,6 +395,7 @@ public final class CraftServer implements Server { + if (this.configuration.getBoolean("settings.use-map-color-cache")) { + MapPalette.setMapColorCache(new CraftMapColorCache(this.logger)); + } ++ this.potionBrewer = new io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes + datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper + } + +@@ -3066,5 +3068,9 @@ public final class CraftServer implements Server { + return datapackManager; + } + ++ @Override ++ public io.papermc.paper.potion.PaperPotionBrewer getPotionBrewer() { ++ return this.potionBrewer; ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +index 6d955c0d2ae166fb39fa38c604729c9a66132352..a30950287646524c4906574d193ec7ce94b4eb34 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +@@ -25,6 +25,11 @@ public interface CraftRecipe extends Recipe { + } + + default Ingredient toNMS(RecipeChoice bukkit, boolean requireNotEmpty) { ++ // Paper start ++ return toIngredient(bukkit, requireNotEmpty); ++ } ++ static Ingredient toIngredient(RecipeChoice bukkit, boolean requireNotEmpty) { ++ // Paper end + Ingredient stack; + + if (bukkit == null) { diff --git a/patches/server/0664-Put-world-into-worldlist-before-initing-the-world.patch b/patches/server/0664-Put-world-into-worldlist-before-initing-the-world.patch deleted file mode 100644 index 9dff7a427d..0000000000 --- a/patches/server/0664-Put-world-into-worldlist-before-initing-the-world.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 22 Feb 2022 14:21:35 -0800 -Subject: [PATCH] Put world into worldlist before initing the world - -Some parts of legacy conversion will need the overworld -to get the legacy structure data storage - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index c5ee4c255ae7a1f0dc662f0d375607935e5e097a..7aef3396a3580996044cd15d2ca26c11327513a1 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -659,9 +659,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Thu, 7 Oct 2021 14:34:55 -0700 -Subject: [PATCH] Custom Potion Mixes - -== AT == -public-f net.minecraft.server.MinecraftServer potionBrewing - -diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java b/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d9390227a2bba4e03aa9ee592ca157127633c41b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java -@@ -0,0 +1,56 @@ -+package io.papermc.paper.potion; -+ -+import com.google.common.base.Preconditions; -+import java.util.Collection; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.NamespacedKey; -+import org.bukkit.potion.PotionBrewer; -+import org.bukkit.potion.PotionEffect; -+import org.bukkit.potion.PotionType; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public class PaperPotionBrewer implements PotionBrewer { -+ -+ private final MinecraftServer minecraftServer; -+ -+ public PaperPotionBrewer(final MinecraftServer minecraftServer) { -+ this.minecraftServer = minecraftServer; -+ } -+ -+ @Override -+ @Deprecated(forRemoval = true) -+ public Collection getEffects(PotionType type, boolean upgraded, boolean extended) { -+ final org.bukkit.NamespacedKey key = type.getKey(); -+ -+ Preconditions.checkArgument(!key.getKey().startsWith("strong_"), "Strong potion type cannot be used directly, got %s", key); -+ Preconditions.checkArgument(!key.getKey().startsWith("long_"), "Extended potion type cannot be used directly, got %s", key); -+ -+ org.bukkit.NamespacedKey effectiveKey = key; -+ if (upgraded) { -+ effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "strong_" + key.key()); -+ } else if (extended) { -+ effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "long_" + key.key()); -+ } -+ -+ final org.bukkit.potion.PotionType effectivePotionType = org.bukkit.Registry.POTION.get(effectiveKey); -+ Preconditions.checkNotNull(type, "Unknown potion type from data " + effectiveKey.asMinimalString()); // Legacy error message in 1.20.4 -+ return effectivePotionType.getPotionEffects(); -+ } -+ -+ @Override -+ public void addPotionMix(final PotionMix potionMix) { -+ this.minecraftServer.potionBrewing().addPotionMix(potionMix); -+ } -+ -+ @Override -+ public void removePotionMix(final NamespacedKey key) { -+ this.minecraftServer.potionBrewing.removePotionMix(key); -+ } -+ -+ @Override -+ public void resetPotionMixes() { -+ this.minecraftServer.potionBrewing = this.minecraftServer.potionBrewing().reload(this.minecraftServer.getWorldData().enabledFeatures()); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionMix.java b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7ea357ac2f3a93db4ebdf24b5072be7d1cad3e33 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java -@@ -0,0 +1,21 @@ -+package io.papermc.paper.potion; -+ -+import java.util.function.Predicate; -+import net.minecraft.world.item.ItemStack; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.craftbukkit.inventory.CraftRecipe; -+import org.bukkit.inventory.RecipeChoice; -+ -+public record PaperPotionMix(ItemStack result, Predicate input, Predicate ingredient) { -+ -+ public PaperPotionMix(PotionMix potionMix) { -+ this(CraftItemStack.asNMSCopy(potionMix.getResult()), convert(potionMix.getInput()), convert(potionMix.getIngredient())); -+ } -+ -+ static Predicate convert(final RecipeChoice choice) { -+ if (choice instanceof PredicateRecipeChoice predicateRecipeChoice) { -+ return stack -> predicateRecipeChoice.test(CraftItemStack.asBukkitCopy(stack)); -+ } -+ return CraftRecipe.toIngredient(choice, true); -+ } -+} -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7aef3396a3580996044cd15d2ca26c11327513a1..3b0f7e7a5bea786f1189d6e47d8dfd7107d66a53 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2240,6 +2240,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop containers; - private final List> potionMixes; - private final List> containerMixes; -+ private final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap customMixes = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper - Custom Potion Mixes - - PotionBrewing(List potionTypes, List> potionRecipes, List> itemRecipes) { - this.containers = potionTypes; -@@ -27,7 +28,7 @@ public class PotionBrewing { - } - - public boolean isIngredient(ItemStack stack) { -- return this.isContainerIngredient(stack) || this.isPotionIngredient(stack); -+ return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || this.isCustomIngredient(stack); // Paper - Custom Potion Mixes - } - - private boolean isContainer(ItemStack stack) { -@@ -71,6 +72,11 @@ public class PotionBrewing { - } - - public boolean hasMix(ItemStack input, ItemStack ingredient) { -+ // Paper start - Custom Potion Mixes -+ if (this.hasCustomMix(input, ingredient)) { -+ return true; -+ } -+ // Paper end - Custom Potion Mixes - return this.isContainer(input) && (this.hasContainerMix(input, ingredient) || this.hasPotionMix(input, ingredient)); - } - -@@ -103,6 +109,13 @@ public class PotionBrewing { - if (input.isEmpty()) { - return input; - } else { -+ // Paper start - Custom Potion Mixes -+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { -+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) { -+ return mix.result().copy(); -+ } -+ } -+ // Paper end - Custom Potion Mixes - Optional> optional = input.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion(); - if (optional.isEmpty()) { - return input; -@@ -190,6 +203,50 @@ public class PotionBrewing { - builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING); - } - -+ // Paper start - Custom Potion Mixes -+ public boolean isCustomIngredient(ItemStack stack) { -+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { -+ if (mix.ingredient().test(stack)) { -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ public boolean isCustomInput(ItemStack stack) { -+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { -+ if (mix.input().test(stack)) { -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ private boolean hasCustomMix(ItemStack input, ItemStack ingredient) { -+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { -+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) { -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ public void addPotionMix(io.papermc.paper.potion.PotionMix mix) { -+ if (this.customMixes.containsKey(mix.getKey())) { -+ throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey()); -+ } -+ this.customMixes.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix)); -+ } -+ -+ public boolean removePotionMix(org.bukkit.NamespacedKey key) { -+ return this.customMixes.remove(key) != null; -+ } -+ -+ public PotionBrewing reload(FeatureFlagSet flags) { -+ return bootstrap(flags); -+ } -+ // Paper end - Custom Potion Mixes -+ - public static class Builder { - private final List containers = new ArrayList<>(); - private final List> potionMixes = new ArrayList<>(); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -index e167c2834f1b7899a7d11cef782940deeb739a9c..2bafacd7bc56186d9105d2031180f8c4a6940018 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -@@ -316,12 +316,12 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements - - @Override - public boolean canPlaceItem(int slot, ItemStack stack) { -+ PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; // Paper - move up - if (slot == 3) { -- PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; - - return potionbrewer.isIngredient(stack); - } else { -- return slot == 4 ? stack.is(ItemTags.BREWING_FUEL) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE)) && this.getItem(slot).isEmpty(); -+ return slot == 4 ? stack.is(ItemTags.BREWING_FUEL) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionbrewer.isCustomInput(stack)) && this.getItem(slot).isEmpty(); // Paper - Custom Potion Mixes - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index ba4c184e25fa1c288e70815b760d3ef1b364d9fd..b3e5fc3a417be2af8ed6591f67f8d56c4ca86d74 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -311,6 +311,7 @@ public final class CraftServer implements Server { - private final io.papermc.paper.datapack.PaperDatapackManager datapackManager; // Paper - public static Exception excessiveVelEx; // Paper - Velocity warnings - private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher(); // Paper -+ private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer; // Paper - Custom Potion Mixes - - static { - ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); -@@ -395,6 +396,7 @@ public final class CraftServer implements Server { - if (this.configuration.getBoolean("settings.use-map-color-cache")) { - MapPalette.setMapColorCache(new CraftMapColorCache(this.logger)); - } -+ this.potionBrewer = new io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes - datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper - } - -@@ -3067,5 +3069,9 @@ public final class CraftServer implements Server { - return datapackManager; - } - -+ @Override -+ public io.papermc.paper.potion.PaperPotionBrewer getPotionBrewer() { -+ return this.potionBrewer; -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -index 6d955c0d2ae166fb39fa38c604729c9a66132352..a30950287646524c4906574d193ec7ce94b4eb34 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -@@ -25,6 +25,11 @@ public interface CraftRecipe extends Recipe { - } - - default Ingredient toNMS(RecipeChoice bukkit, boolean requireNotEmpty) { -+ // Paper start -+ return toIngredient(bukkit, requireNotEmpty); -+ } -+ static Ingredient toIngredient(RecipeChoice bukkit, boolean requireNotEmpty) { -+ // Paper end - Ingredient stack; - - if (bukkit == null) { diff --git a/patches/server/0665-Force-close-world-loading-screen.patch b/patches/server/0665-Force-close-world-loading-screen.patch new file mode 100644 index 0000000000..481f82aff5 --- /dev/null +++ b/patches/server/0665-Force-close-world-loading-screen.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Wed, 2 Mar 2022 09:45:56 +0100 +Subject: [PATCH] Force close world loading screen + +Dead players would be stuck in the world loading screen and other players may +miss messages and similar sent in the join event if chunk loading is slow. +Paper already circumvents falling through the world before chunks are loaded, +so we do not need that. The client only needs the chunk it is currently in to +be loaded to close the loading screen, so we just send an empty one. + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 2497aeb46ff4188948e9253c21d83a218fd73e85..f1530fbcaf9913e43143b40117fb7fe63b326d1d 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -406,6 +406,16 @@ public abstract class PlayerList { + } + // Paper end - Configurable player collision + PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); ++ // Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead ++ if (player.isDeadOrDying()) { ++ net.minecraft.core.Holder plains = worldserver1.registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME) ++ .getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS); ++ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket( ++ new net.minecraft.world.level.chunk.EmptyLevelChunk(worldserver1, player.chunkPosition(), plains), ++ worldserver1.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null) ++ ); ++ } ++ // Paper end - Send empty chunk + } + + public void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) { diff --git a/patches/server/0666-Fix-falling-block-spawn-methods.patch b/patches/server/0666-Fix-falling-block-spawn-methods.patch new file mode 100644 index 0000000000..771588bb12 --- /dev/null +++ b/patches/server/0666-Fix-falling-block-spawn-methods.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Fri, 4 Mar 2022 20:35:19 +0100 +Subject: [PATCH] Fix falling block spawn methods + +Restores the API behavior from previous versions of the server +- Do not call API events +- Do not replace the existing block in the world + +== AT == +public net.minecraft.world.entity.item.FallingBlockEntity (Lnet/minecraft/world/level/Level;DDDLnet/minecraft/world/level/block/state/BlockState;)V + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 0ff12d4e74c14b2b0ecf06d720c5e06edb35fcdb..9240460b9ec582ac01d3074c9bc923191bf0ad95 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1405,7 +1405,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { + Preconditions.checkArgument(material != null, "Material cannot be null"); + Preconditions.checkArgument(material.isBlock(), "Material.%s must be a block", material); + +- FallingBlockEntity entity = FallingBlockEntity.fall(this.world, BlockPos.containing(location.getX(), location.getY(), location.getZ()), CraftBlockType.bukkitToMinecraft(material).defaultBlockState(), SpawnReason.CUSTOM); ++ // Paper start - restore API behavior for spawning falling blocks ++ FallingBlockEntity entity = new FallingBlockEntity(this.world, location.getX(), location.getY(), location.getZ(), CraftBlockType.bukkitToMinecraft(material).defaultBlockState()); // Paper ++ entity.time = 1; ++ ++ this.world.addFreshEntity(entity, SpawnReason.CUSTOM); ++ // Paper end - restore API behavior for spawning falling blocks + return (FallingBlock) entity.getBukkitEntity(); + } + +@@ -1414,7 +1419,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { + Preconditions.checkArgument(location != null, "Location cannot be null"); + Preconditions.checkArgument(data != null, "BlockData cannot be null"); + +- FallingBlockEntity entity = FallingBlockEntity.fall(this.world, BlockPos.containing(location.getX(), location.getY(), location.getZ()), ((CraftBlockData) data).getState(), SpawnReason.CUSTOM); ++ // Paper start - restore API behavior for spawning falling blocks ++ FallingBlockEntity entity = new FallingBlockEntity(this.world, location.getX(), location.getY(), location.getZ(), ((CraftBlockData) data).getState()); ++ entity.time = 1; ++ ++ this.world.addFreshEntity(entity, SpawnReason.CUSTOM); ++ // Paper end - restore API behavior for spawning falling blocks + return (FallingBlock) entity.getBukkitEntity(); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +index 42ecef3dbb888ba716b6f63335efca6fb0f27457..b79e72a77178f755957ef391b6444a357bdefbd0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -440,7 +440,7 @@ public final class CraftEntityTypes { + register(new EntityTypeData<>(EntityType.TNT, TNTPrimed.class, CraftTNTPrimed::new, spawnData -> new PrimedTnt(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null))); + register(new EntityTypeData<>(EntityType.FALLING_BLOCK, FallingBlock.class, CraftFallingBlock::new, spawnData -> { + BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z()); +- return FallingBlockEntity.fall(spawnData.minecraftWorld(), pos, spawnData.world().getBlockState(pos)); ++ return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly + })); + register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), net.minecraft.world.item.ItemStack.EMPTY))); + register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null))); diff --git a/patches/server/0666-Force-close-world-loading-screen.patch b/patches/server/0666-Force-close-world-loading-screen.patch deleted file mode 100644 index edae404607..0000000000 --- a/patches/server/0666-Force-close-world-loading-screen.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Wed, 2 Mar 2022 09:45:56 +0100 -Subject: [PATCH] Force close world loading screen - -Dead players would be stuck in the world loading screen and other players may -miss messages and similar sent in the join event if chunk loading is slow. -Paper already circumvents falling through the world before chunks are loaded, -so we do not need that. The client only needs the chunk it is currently in to -be loaded to close the loading screen, so we just send an empty one. - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f34cad30c982f2bb563f0deab030111720858fa8..215a3c9839d664f6cfd4c9360338abcf5863799a 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -407,6 +407,16 @@ public abstract class PlayerList { - } - // Paper end - Configurable player collision - PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); -+ // Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead -+ if (player.isDeadOrDying()) { -+ net.minecraft.core.Holder plains = worldserver1.registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME) -+ .getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS); -+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket( -+ new net.minecraft.world.level.chunk.EmptyLevelChunk(worldserver1, player.chunkPosition(), plains), -+ worldserver1.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null) -+ ); -+ } -+ // Paper end - Send empty chunk - } - - public void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) { diff --git a/patches/server/0667-Expose-furnace-minecart-push-values.patch b/patches/server/0667-Expose-furnace-minecart-push-values.patch new file mode 100644 index 0000000000..fb48aabb5f --- /dev/null +++ b/patches/server/0667-Expose-furnace-minecart-push-values.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: EpicKnarvik97 +Date: Sat, 5 Mar 2022 20:58:46 +0100 +Subject: [PATCH] Expose furnace minecart push values + +Adds methods for getting and setting a furnace minecart's push values + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java +index 53042b75b45093535d6572239b34c3ff9a72f648..1be1f6d23f2224d4d8720d40f2e530736b1bae81 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java +@@ -27,6 +27,30 @@ public class CraftMinecartFurnace extends CraftMinecart implements PoweredMineca + this.getHandle().fuel = fuel; + } + ++ // Paper start ++ @Override ++ public double getPushX() { ++ return getHandle().push.x; ++ } ++ ++ @Override ++ public double getPushZ() { ++ return getHandle().push.z; ++ } ++ ++ @Override ++ public void setPushX(double xPush) { ++ final net.minecraft.world.phys.Vec3 push = getHandle().push; ++ getHandle().push = new net.minecraft.world.phys.Vec3(xPush, push.y, push.z); ++ } ++ ++ @Override ++ public void setPushZ(double zPush) { ++ final net.minecraft.world.phys.Vec3 push = getHandle().push; ++ getHandle().push = new net.minecraft.world.phys.Vec3(push.x, push.y, zPush); ++ } ++ // Paper end ++ + @Override + public String toString() { + return "CraftMinecartFurnace"; diff --git a/patches/server/0667-Fix-falling-block-spawn-methods.patch b/patches/server/0667-Fix-falling-block-spawn-methods.patch deleted file mode 100644 index 771588bb12..0000000000 --- a/patches/server/0667-Fix-falling-block-spawn-methods.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Fri, 4 Mar 2022 20:35:19 +0100 -Subject: [PATCH] Fix falling block spawn methods - -Restores the API behavior from previous versions of the server -- Do not call API events -- Do not replace the existing block in the world - -== AT == -public net.minecraft.world.entity.item.FallingBlockEntity (Lnet/minecraft/world/level/Level;DDDLnet/minecraft/world/level/block/state/BlockState;)V - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 0ff12d4e74c14b2b0ecf06d720c5e06edb35fcdb..9240460b9ec582ac01d3074c9bc923191bf0ad95 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1405,7 +1405,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - Preconditions.checkArgument(material != null, "Material cannot be null"); - Preconditions.checkArgument(material.isBlock(), "Material.%s must be a block", material); - -- FallingBlockEntity entity = FallingBlockEntity.fall(this.world, BlockPos.containing(location.getX(), location.getY(), location.getZ()), CraftBlockType.bukkitToMinecraft(material).defaultBlockState(), SpawnReason.CUSTOM); -+ // Paper start - restore API behavior for spawning falling blocks -+ FallingBlockEntity entity = new FallingBlockEntity(this.world, location.getX(), location.getY(), location.getZ(), CraftBlockType.bukkitToMinecraft(material).defaultBlockState()); // Paper -+ entity.time = 1; -+ -+ this.world.addFreshEntity(entity, SpawnReason.CUSTOM); -+ // Paper end - restore API behavior for spawning falling blocks - return (FallingBlock) entity.getBukkitEntity(); - } - -@@ -1414,7 +1419,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - Preconditions.checkArgument(location != null, "Location cannot be null"); - Preconditions.checkArgument(data != null, "BlockData cannot be null"); - -- FallingBlockEntity entity = FallingBlockEntity.fall(this.world, BlockPos.containing(location.getX(), location.getY(), location.getZ()), ((CraftBlockData) data).getState(), SpawnReason.CUSTOM); -+ // Paper start - restore API behavior for spawning falling blocks -+ FallingBlockEntity entity = new FallingBlockEntity(this.world, location.getX(), location.getY(), location.getZ(), ((CraftBlockData) data).getState()); -+ entity.time = 1; -+ -+ this.world.addFreshEntity(entity, SpawnReason.CUSTOM); -+ // Paper end - restore API behavior for spawning falling blocks - return (FallingBlock) entity.getBukkitEntity(); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -index 42ecef3dbb888ba716b6f63335efca6fb0f27457..b79e72a77178f755957ef391b6444a357bdefbd0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -440,7 +440,7 @@ public final class CraftEntityTypes { - register(new EntityTypeData<>(EntityType.TNT, TNTPrimed.class, CraftTNTPrimed::new, spawnData -> new PrimedTnt(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null))); - register(new EntityTypeData<>(EntityType.FALLING_BLOCK, FallingBlock.class, CraftFallingBlock::new, spawnData -> { - BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z()); -- return FallingBlockEntity.fall(spawnData.minecraftWorld(), pos, spawnData.world().getBlockState(pos)); -+ return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly - })); - register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), net.minecraft.world.item.ItemStack.EMPTY))); - register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null))); diff --git a/patches/server/0668-Expose-furnace-minecart-push-values.patch b/patches/server/0668-Expose-furnace-minecart-push-values.patch deleted file mode 100644 index fb48aabb5f..0000000000 --- a/patches/server/0668-Expose-furnace-minecart-push-values.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: EpicKnarvik97 -Date: Sat, 5 Mar 2022 20:58:46 +0100 -Subject: [PATCH] Expose furnace minecart push values - -Adds methods for getting and setting a furnace minecart's push values - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java -index 53042b75b45093535d6572239b34c3ff9a72f648..1be1f6d23f2224d4d8720d40f2e530736b1bae81 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java -@@ -27,6 +27,30 @@ public class CraftMinecartFurnace extends CraftMinecart implements PoweredMineca - this.getHandle().fuel = fuel; - } - -+ // Paper start -+ @Override -+ public double getPushX() { -+ return getHandle().push.x; -+ } -+ -+ @Override -+ public double getPushZ() { -+ return getHandle().push.z; -+ } -+ -+ @Override -+ public void setPushX(double xPush) { -+ final net.minecraft.world.phys.Vec3 push = getHandle().push; -+ getHandle().push = new net.minecraft.world.phys.Vec3(xPush, push.y, push.z); -+ } -+ -+ @Override -+ public void setPushZ(double zPush) { -+ final net.minecraft.world.phys.Vec3 push = getHandle().push; -+ getHandle().push = new net.minecraft.world.phys.Vec3(push.x, push.y, zPush); -+ } -+ // Paper end -+ - @Override - public String toString() { - return "CraftMinecartFurnace"; diff --git a/patches/server/0668-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch b/patches/server/0668-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch new file mode 100644 index 0000000000..7a72849b26 --- /dev/null +++ b/patches/server/0668-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 19 Feb 2022 19:05:59 -0800 +Subject: [PATCH] Fix cancelling ProjectileHitEvent for piercing arrows + +Piercing arrows search for multiple entities inside a while +loop that is checking the projectile entity's removed state. +If the hit event is cancelled on the first entity, the event will +be called over and over again inside that while loop until the event +is not cancelled. The solution here, is to make use of an +already-existing field on AbstractArrow for tracking entities hit by +piercing arrows to avoid duplicate damage being applied. + +== AT == +protected net.minecraft.world.entity.projectile.Projectile hitCancelled + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +index 44bcb1117cfa4d66c500011489ae193a0d1e7d78..75cc3db39c974abab8510af4a633fc6812efc647 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -344,6 +344,19 @@ public abstract class AbstractArrow extends Projectile { + + } + ++ // Paper start - Fix cancelling ProjectileHitEvent for piercing arrows ++ @Override ++ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult hitResult) { ++ if (hitResult instanceof EntityHitResult entityHitResult && this.hitCancelled && this.getPierceLevel() > 0) { ++ if (this.piercingIgnoreEntityIds == null) { ++ this.piercingIgnoreEntityIds = new IntOpenHashSet(5); ++ } ++ this.piercingIgnoreEntityIds.add(entityHitResult.getEntity().getId()); ++ } ++ return super.preHitTargetOrDeflectSelf(hitResult); ++ } ++ // Paper end - Fix cancelling ProjectileHitEvent for piercing arrows ++ + @Override + protected double getDefaultGravity() { + return 0.05D; diff --git a/patches/server/0669-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch b/patches/server/0669-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch deleted file mode 100644 index 7a72849b26..0000000000 --- a/patches/server/0669-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 19 Feb 2022 19:05:59 -0800 -Subject: [PATCH] Fix cancelling ProjectileHitEvent for piercing arrows - -Piercing arrows search for multiple entities inside a while -loop that is checking the projectile entity's removed state. -If the hit event is cancelled on the first entity, the event will -be called over and over again inside that while loop until the event -is not cancelled. The solution here, is to make use of an -already-existing field on AbstractArrow for tracking entities hit by -piercing arrows to avoid duplicate damage being applied. - -== AT == -protected net.minecraft.world.entity.projectile.Projectile hitCancelled - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -index 44bcb1117cfa4d66c500011489ae193a0d1e7d78..75cc3db39c974abab8510af4a633fc6812efc647 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -344,6 +344,19 @@ public abstract class AbstractArrow extends Projectile { - - } - -+ // Paper start - Fix cancelling ProjectileHitEvent for piercing arrows -+ @Override -+ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult hitResult) { -+ if (hitResult instanceof EntityHitResult entityHitResult && this.hitCancelled && this.getPierceLevel() > 0) { -+ if (this.piercingIgnoreEntityIds == null) { -+ this.piercingIgnoreEntityIds = new IntOpenHashSet(5); -+ } -+ this.piercingIgnoreEntityIds.add(entityHitResult.getEntity().getId()); -+ } -+ return super.preHitTargetOrDeflectSelf(hitResult); -+ } -+ // Paper end - Fix cancelling ProjectileHitEvent for piercing arrows -+ - @Override - protected double getDefaultGravity() { - return 0.05D; diff --git a/patches/server/0669-More-Projectile-API.patch b/patches/server/0669-More-Projectile-API.patch new file mode 100644 index 0000000000..9f9c1e0dd4 --- /dev/null +++ b/patches/server/0669-More-Projectile-API.patch @@ -0,0 +1,932 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 22 Jun 2021 23:41:11 -0400 +Subject: [PATCH] More Projectile API + +== AT == +public net.minecraft.world.entity.projectile.FishingHook timeUntilLured +public net.minecraft.world.entity.projectile.FishingHook fishAngle +public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaX +public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaY +public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaZ +public net.minecraft.world.entity.projectile.ShulkerBullet currentMoveDirection +public net.minecraft.world.entity.projectile.ShulkerBullet flightSteps +public net.minecraft.world.entity.projectile.AbstractArrow soundEvent +public net.minecraft.world.entity.projectile.AbstractArrow setPickupItemStack(Lnet/minecraft/world/item/ItemStack;)V +public net.minecraft.world.entity.projectile.ThrownTrident dealtDamage +public net.minecraft.world.entity.projectile.Arrow NO_EFFECT_COLOR +public net.minecraft.world.entity.projectile.Projectile hasBeenShot +public net.minecraft.world.entity.projectile.Projectile leftOwner +public net.minecraft.world.entity.projectile.Projectile ownerUUID +public net.minecraft.world.entity.projectile.Projectile preOnHit(Lnet/minecraft/world/phys/HitResult;)V +public net.minecraft.world.entity.projectile.Projectile canHitEntity(Lnet/minecraft/world/entity/Entity;)Z +public net.minecraft.world.entity.projectile.FireworkRocketEntity getDefaultItem()Lnet/minecraft/world/item/ItemStack; +public net.minecraft.world.item.CrossbowItem FIREWORK_POWER + +Co-authored-by: Nassim Jahnke +Co-authored-by: SoSeDiK +Co-authored-by: MelnCat +Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java +index 536196a740f607adda2a5ae7f644981ac26bef98..1f95234c0a1457050574aa0f6c4b2a8c91b1f272 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java +@@ -419,13 +419,18 @@ public class FishingHook extends Projectile { + } + } else { + // CraftBukkit start - logic to modify fishing wait time +- this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime); +- this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop ++ this.resetTimeUntilLured(); // Paper - more projectile api - extract time until lured reset logic + // CraftBukkit end + } + } + + } ++ // Paper start - more projectile api - extract time until lured reset logic ++ public void resetTimeUntilLured() { ++ this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime); ++ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop ++ } ++ // Paper end - more projectile api - extract time until lured reset logic + + public boolean calculateOpenWater(BlockPos pos) { + FishingHook.OpenWaterType entityfishinghook_waterposition = FishingHook.OpenWaterType.INVALID; +diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +index 09d1131c7f2b32b6c032341a60521608b098c109..824090367e833c57a22c1017981f0508b28a35d2 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +@@ -288,7 +288,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { + } + + // CraftBukkit start - call projectile hit event +- protected ProjectileDeflection preHitTargetOrDeflectSelf(HitResult movingobjectposition) { ++ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult movingobjectposition) { // Paper - protected -> public + org.bukkit.event.entity.ProjectileHitEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this, movingobjectposition); + this.hitCancelled = event != null && event.isCancelled(); + if (movingobjectposition.getType() == HitResult.Type.BLOCK || !this.hitCancelled) { +diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +index d6ac07d9d5ee0430a1d91b7084b378aac1d047e5..a486466040a646b8a5a5ff2430cdd25b95b7e20f 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +@@ -103,8 +103,12 @@ public class ThrownPotion extends ThrowableItemProjectile { + @Override + protected void onHit(HitResult hitResult) { + super.onHit(hitResult); ++ // Paper start - More projectile API ++ this.splash(hitResult); ++ } ++ public void splash(@Nullable HitResult hitResult) { ++ // Paper end - More projectile API + Level world = this.level(); +- + if (world instanceof ServerLevel worldserver) { + ItemStack itemstack = this.getItem(); + PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); +@@ -116,7 +120,7 @@ public class ThrownPotion extends ThrowableItemProjectile { + if (this.isLingering()) { + showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper + } else { +- showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper ++ showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult != null && hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API + } + } + +@@ -178,7 +182,7 @@ public class ThrownPotion extends ThrowableItemProjectile { + + } + +- private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events ++ private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events & More projectile API + AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); + List list = worldserver.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb); + Map affected = new HashMap(); // CraftBukkit +@@ -256,7 +260,7 @@ public class ThrownPotion extends ThrowableItemProjectile { + + } + +- private boolean makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition ++ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API + AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); + Entity entity = this.getOwner(); + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java +index 91c2d0b40d3fca86938cd454e1415a4eea3df7c7..de4fb2654c7895cfd83ad694455ee56cb708c2f2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java +@@ -17,4 +17,65 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti + @Override + public void setBounce(boolean doesBounce) {} + ++ // Paper start - More projectile API ++ @Override ++ public boolean hasLeftShooter() { ++ return this.getHandle().leftOwner; ++ } ++ ++ @Override ++ public void setHasLeftShooter(boolean leftShooter) { ++ this.getHandle().leftOwner = leftShooter; ++ } ++ ++ @Override ++ public boolean hasBeenShot() { ++ return this.getHandle().hasBeenShot; ++ } ++ ++ @Override ++ public void setHasBeenShot(boolean beenShot) { ++ this.getHandle().hasBeenShot = beenShot; ++ } ++ ++ @Override ++ public boolean canHitEntity(org.bukkit.entity.Entity entity) { ++ return this.getHandle().canHitEntity(((CraftEntity) entity).getHandle()); ++ } ++ ++ @Override ++ public void hitEntity(org.bukkit.entity.Entity entity) { ++ this.getHandle().preHitTargetOrDeflectSelf(new net.minecraft.world.phys.EntityHitResult(((CraftEntity) entity).getHandle())); ++ } ++ ++ @Override ++ public void hitEntity(org.bukkit.entity.Entity entity, org.bukkit.util.Vector vector) { ++ this.getHandle().preHitTargetOrDeflectSelf(new net.minecraft.world.phys.EntityHitResult(((CraftEntity) entity).getHandle(), new net.minecraft.world.phys.Vec3(vector.getX(), vector.getY(), vector.getZ()))); ++ } ++ ++ @Override ++ public net.minecraft.world.entity.projectile.Projectile getHandle() { ++ return (net.minecraft.world.entity.projectile.Projectile) entity; ++ } ++ ++ @Override ++ public final org.bukkit.projectiles.ProjectileSource getShooter() { ++ return this.getHandle().projectileSource; ++ } ++ ++ @Override ++ public final void setShooter(org.bukkit.projectiles.ProjectileSource shooter) { ++ if (shooter instanceof CraftEntity craftEntity) { ++ this.getHandle().setOwner(craftEntity.getHandle()); ++ } else { ++ this.getHandle().setOwner(null); ++ } ++ this.getHandle().projectileSource = shooter; ++ } ++ ++ @Override ++ public java.util.UUID getOwnerUniqueId() { ++ return this.getHandle().ownerUUID; ++ } ++ // Paper end - More projectile API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java +index 0f85c1f991469b277bba8b40b087f7224b4b3a85..1f30109abd86b76af343eb5eb75ec3db83ef9417 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java +@@ -59,20 +59,7 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr + this.getHandle().setCritArrow(critical); + } + +- @Override +- public ProjectileSource getShooter() { +- return this.getHandle().projectileSource; +- } +- +- @Override +- public void setShooter(ProjectileSource shooter) { +- if (shooter instanceof Entity) { +- this.getHandle().setOwner(((CraftEntity) shooter).getHandle()); +- } else { +- this.getHandle().setOwner(null); +- } +- this.getHandle().projectileSource = shooter; +- } ++ // Paper - moved to AbstractProjectile + + @Override + public boolean isInBlock() { +@@ -133,6 +120,7 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr + + @Override + public ItemStack getWeapon() { ++ if (this.getHandle().getWeaponItem() == null) return null; // Paper - fix NPE + return CraftItemStack.asBukkitCopy(this.getHandle().getWeaponItem()); + } + +@@ -152,4 +140,37 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr + public String toString() { + return "CraftArrow"; + } ++ ++ // Paper start ++ @Override ++ public CraftItemStack getItemStack() { ++ return CraftItemStack.asCraftMirror(this.getHandle().getPickupItem()); ++ } ++ ++ @Override ++ public void setItemStack(final ItemStack stack) { ++ Preconditions.checkArgument(stack != null, "ItemStack cannot be null"); ++ this.getHandle().setPickupItemStack(CraftItemStack.asNMSCopy(stack)); ++ } ++ ++ @Override ++ public void setLifetimeTicks(int ticks) { ++ this.getHandle().life = ticks; ++ } ++ ++ @Override ++ public int getLifetimeTicks() { ++ return this.getHandle().life; ++ } ++ ++ @Override ++ public org.bukkit.Sound getHitSound() { ++ return org.bukkit.craftbukkit.CraftSound.minecraftToBukkit(this.getHandle().soundEvent); ++ } ++ ++ @Override ++ public void setHitSound(org.bukkit.Sound sound) { ++ this.getHandle().setSoundEvent(org.bukkit.craftbukkit.CraftSound.bukkitToMinecraft(sound)); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java +index 6591513bb62226b6f85fd2ef9f6ebe376f0f7362..f9c113dc018702159345240d6d0de85767afa0c3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java +@@ -125,7 +125,7 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud + + @Override + public Color getColor() { +- return Color.fromRGB(this.getHandle().potionContents.getColor()); ++ return Color.fromRGB(this.getHandle().potionContents.getColor() & 0x00FFFFFF); // Paper - skip alpha channel + } + + @Override +@@ -143,7 +143,7 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud + this.removeCustomEffect(effect.getType()); + } + this.getHandle().addEffect(CraftPotionUtil.fromBukkit(effect)); +- this.getHandle().updateColor(); ++ // this.getHandle().updateColor(); // Paper - already done above + return true; + } + +@@ -151,7 +151,7 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud + public void clearCustomEffects() { + PotionContents old = this.getHandle().potionContents; + this.getHandle().setPotionContents(new PotionContents(old.potion(), old.customColor(), List.of(), old.customName())); +- this.getHandle().updateColor(); ++ // this.getHandle().updateColor(); // Paper - already done above + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java +index 199d5836dc787cca54c6b653a4e67573f2f758a2..15d50a284cafc2eb59239ca00926836526f09e06 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java +@@ -43,7 +43,7 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow { + this.removeCustomEffect(effect.getType()); + } + this.getHandle().addEffect(CraftPotionUtil.fromBukkit(effect)); +- this.getHandle().updateColor(); ++ // this.getHandle().updateColor(); // Paper - already done above + return true; + } + +@@ -51,7 +51,7 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow { + public void clearCustomEffects() { + PotionContents old = this.getHandle().getPotionContents(); + this.getHandle().setPotionContents(new PotionContents(old.potion(), old.customColor(), List.of(), old.customName())); +- this.getHandle().updateColor(); ++ // this.getHandle().updateColor(); // Paper - already done above + } + + @Override +@@ -117,16 +117,17 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow { + + @Override + public void setColor(Color color) { +- int colorRGB = (color == null) ? -1 : color.asRGB(); ++ int colorRGB = (color == null) ? net.minecraft.world.entity.projectile.Arrow.NO_EFFECT_COLOR : color.asARGB(); // Paper + PotionContents old = this.getHandle().getPotionContents(); + this.getHandle().setPotionContents(new PotionContents(old.potion(), Optional.of(colorRGB), old.customEffects(), old.customName())); + } + + @Override + public Color getColor() { +- if (this.getHandle().getColor() <= -1) { ++ int color = this.getHandle().getColor(); // Paper ++ if (color == net.minecraft.world.entity.projectile.Arrow.NO_EFFECT_COLOR) { // Paper + return null; + } +- return Color.fromRGB(this.getHandle().getColor()); ++ return Color.fromARGB(color); // Paper + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +index b79e72a77178f755957ef391b6444a357bdefbd0..39ea25d2145acaa7c7b458800adc674a3e73e7c1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -442,7 +442,7 @@ public final class CraftEntityTypes { + BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z()); + return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly + })); +- register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), net.minecraft.world.item.ItemStack.EMPTY))); ++ register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), FireworkRocketEntity.getDefaultItem()))); // Paper - pass correct default to rocket for data storage + register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null))); + register(new EntityTypeData<>(EntityType.COMMAND_BLOCK_MINECART, CommandMinecart.class, CraftMinecartCommand::new, createMinecart(net.minecraft.world.entity.EntityType.COMMAND_BLOCK_MINECART))); + register(new EntityTypeData<>(EntityType.MINECART, RideableMinecart.class, CraftMinecartRideable::new, createMinecart(net.minecraft.world.entity.EntityType.MINECART))); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java +index 1b084d63bdbb24dad45d28eed1693eb6e26e24dc..43d7bea201a52cfeacf60c75caa28dfd2c4ff164 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java +@@ -34,20 +34,7 @@ public class CraftFireball extends AbstractProjectile implements Fireball { + this.getHandle().bukkitYield = yield; + } + +- @Override +- public ProjectileSource getShooter() { +- return this.getHandle().projectileSource; +- } +- +- @Override +- public void setShooter(ProjectileSource shooter) { +- if (shooter instanceof CraftLivingEntity) { +- this.getHandle().setOwner(((CraftLivingEntity) shooter).getHandle()); +- } else { +- this.getHandle().setOwner(null); +- } +- this.getHandle().projectileSource = shooter; +- } ++ // Paper - moved to AbstractProjectile + + @Override + public Vector getDirection() { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java +index c9e15a9d82dee935293b2e7e233f5b9b2d822448..2d54cf6f3d9696c55335f0a2057025e2034d4e13 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java +@@ -15,24 +15,26 @@ import org.bukkit.inventory.meta.FireworkMeta; + public class CraftFirework extends CraftProjectile implements Firework { + + private final Random random = new Random(); +- private final CraftItemStack item; ++ //private CraftItemStack item; // Paper - Remove usage, not accurate representation of current item. + + public CraftFirework(CraftServer server, FireworkRocketEntity entity) { + super(server, entity); + +- ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM); +- +- if (item.isEmpty()) { +- item = new ItemStack(Items.FIREWORK_ROCKET); +- this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); +- } +- +- this.item = CraftItemStack.asCraftMirror(item); +- +- // Ensure the item is a firework... +- if (this.item.getType() != Material.FIREWORK_ROCKET) { +- this.item.setType(Material.FIREWORK_ROCKET); +- } ++ // Paper start - Expose firework item directly ++// ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM); ++// ++// if (item.isEmpty()) { ++// item = new ItemStack(Items.FIREWORK_ROCKET); ++// this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); ++// } ++// ++// this.item = CraftItemStack.asCraftMirror(item); ++// ++// // Ensure the item is a firework... ++// if (this.item.getType() != Material.FIREWORK_ROCKET) { ++// this.item.setType(Material.FIREWORK_ROCKET); ++// } ++ // Paper end - Expose firework item directly + } + + @Override +@@ -47,12 +49,12 @@ public class CraftFirework extends CraftProjectile implements Firework { + + @Override + public FireworkMeta getFireworkMeta() { +- return (FireworkMeta) this.item.getItemMeta(); ++ return (FireworkMeta) CraftItemStack.getItemMeta(this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM), org.bukkit.inventory.ItemType.FIREWORK_ROCKET); // Paper - Expose firework item directly + } + + @Override + public void setFireworkMeta(FireworkMeta meta) { +- this.item.setItemMeta(meta); ++ applyFireworkEffect(meta); // Paper - Expose firework item directly + + // Copied from EntityFireworks constructor, update firework lifetime/power + this.getHandle().lifetime = 10 * (1 + meta.getPower()) + this.random.nextInt(6) + this.random.nextInt(7); +@@ -136,4 +138,46 @@ public class CraftFirework extends CraftProjectile implements Firework { + return getHandle().spawningEntity; + } + // Paper end ++ // Paper start - Expose firework item directly + manually setting flight ++ @Override ++ public org.bukkit.inventory.ItemStack getItem() { ++ return CraftItemStack.asBukkitCopy(this.getHandle().getItem()); ++ } ++ ++ @Override ++ public void setItem(org.bukkit.inventory.ItemStack itemStack) { ++ FireworkMeta meta = getFireworkMeta(); ++ ItemStack nmsItem = itemStack == null ? FireworkRocketEntity.getDefaultItem() : CraftItemStack.asNMSCopy(itemStack); ++ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, nmsItem); ++ ++ applyFireworkEffect(meta); ++ } ++ ++ @Override ++ public int getTicksFlown() { ++ return this.getHandle().life; ++ } ++ ++ @Override ++ public void setTicksFlown(int ticks) { ++ this.getHandle().life = ticks; ++ } ++ ++ @Override ++ public int getTicksToDetonate() { ++ return this.getHandle().lifetime; ++ } ++ ++ @Override ++ public void setTicksToDetonate(int ticks) { ++ this.getHandle().lifetime = ticks; ++ } ++ ++ void applyFireworkEffect(FireworkMeta meta) { ++ ItemStack item = this.getHandle().getItem(); ++ CraftItemStack.applyMetaToItem(item, meta); ++ ++ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); ++ } ++ // Paper end - Expose firework item directly + manually setting flight + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java +index 6e2f91423371ead9890095cf4b1e2299c4dcba28..9d8f4b7176e60180565e3134a14ecf19060f2621 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java +@@ -196,4 +196,42 @@ public class CraftFishHook extends CraftProjectile implements FishHook { + public HookState getState() { + return HookState.values()[this.getHandle().currentState.ordinal()]; + } ++ // Paper start - More FishHook API ++ @Override ++ public int getWaitTime() { ++ return this.getHandle().timeUntilLured; ++ } ++ ++ @Override ++ public void setWaitTime(int ticks) { ++ this.getHandle().timeUntilLured = ticks; ++ } ++ ++ @Override ++ public int getTimeUntilBite() { ++ return this.getHandle().timeUntilHooked; ++ } ++ ++ @Override ++ public void setTimeUntilBite(final int ticks) { ++ com.google.common.base.Preconditions.checkArgument(ticks >= 1, "Cannot set time until bite to less than 1 (%s<1)", ticks); ++ final FishingHook hook = this.getHandle(); ++ ++ // Reset the fish angle hook only when this call "enters" the fish into the lure stage. ++ final boolean alreadyInLuringPhase = hook.timeUntilHooked > 0 && hook.timeUntilLured <= 0; ++ if (!alreadyInLuringPhase) { ++ hook.fishAngle = net.minecraft.util.Mth.nextFloat(hook.random, hook.minLureAngle, hook.maxLureAngle); ++ hook.timeUntilLured = 0; ++ } ++ ++ hook.timeUntilHooked = ticks; ++ } ++ ++ @Override ++ public void resetFishingState() { ++ final FishingHook hook = this.getHandle(); ++ hook.resetTimeUntilLured(); ++ hook.timeUntilHooked = 0; // Reset time until hooked, will be repopulated once lured time is ticked down. ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index e148239d4930e5cbb000beed4de386f992f28d88..14b4c3835388d957653ba34444968bb718ce7f68 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -579,8 +579,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + } + + @Override +- @SuppressWarnings("unchecked") + public T launchProjectile(Class projectile, Vector velocity) { ++ // Paper start - launchProjectile consumer ++ return this.launchProjectile(projectile, velocity, null); ++ } ++ ++ @Override ++ @SuppressWarnings("unchecked") ++ public T launchProjectile(Class projectile, Vector velocity, java.util.function.Consumer function) { ++ // Paper end - launchProjectile consumer + Preconditions.checkState(!this.getHandle().generation, "Cannot launch projectile during world generation"); + + net.minecraft.world.level.Level world = ((CraftWorld) this.getWorld()).getHandle(); +@@ -606,7 +613,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + } else { + launch = new net.minecraft.world.entity.projectile.Arrow(world, this.getHandle(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.ARROW), null); + } +- ((net.minecraft.world.entity.projectile.AbstractArrow) launch).shootFromRotation(this.getHandle(), this.getHandle().getXRot(), this.getHandle().getYRot(), 0.0F, 3.0F, 1.0F); // ItemBow ++ ((net.minecraft.world.entity.projectile.AbstractArrow) launch).shootFromRotation(this.getHandle(), this.getHandle().getXRot(), this.getHandle().getYRot(), 0.0F, Trident.class.isAssignableFrom(projectile) ? net.minecraft.world.item.TridentItem.SHOOT_POWER : 3.0F, 1.0F); // ItemBow // Paper - see TridentItem + } else if (ThrownPotion.class.isAssignableFrom(projectile)) { + if (LingeringPotion.class.isAssignableFrom(projectile)) { + launch = new net.minecraft.world.entity.projectile.ThrownPotion(world, this.getHandle(), new net.minecraft.world.item.ItemStack(Items.LINGERING_POTION)); +@@ -663,8 +670,26 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + } else if (Firework.class.isAssignableFrom(projectile)) { + Location location = this.getEyeLocation(); + +- launch = new FireworkRocketEntity(world, net.minecraft.world.item.ItemStack.EMPTY, this.getHandle()); +- launch.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); ++ // Paper start - see CrossbowItem ++ launch = new FireworkRocketEntity(world, FireworkRocketEntity.getDefaultItem(), this.getHandle(), location.getX(), location.getY() - 0.15F, location.getZ(), true); // Paper - pass correct default to rocket for data storage & see CrossbowItem for regular launch without elytra boost ++ ++ // Lifted from net.minecraft.world.item.ProjectileWeaponItem.shoot ++ float f2 = /* net.minecraft.world.item.enchantment.EnchantmentHelper.processProjectileSpread((ServerLevel) world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.CROSSBOW), this.getHandle(), 0.0F); */ 0; // Just shortcut this to 0, no need to do any calculations on a non existing stack ++ int projectileSize = 1; ++ int i = 0; ++ ++ float f3 = projectileSize == 1 ? 0.0F : 2.0F * f2 / (float) (projectileSize - 1); ++ float f4 = (float) ((projectileSize - 1) % 2) * f3 / 2.0F; ++ float f5 = 1.0F; ++ float yaw = f4 + f5 * (float) ((i + 1) / 2) * f3; ++ ++ // Lifted from net.minecraft.world.item.CrossbowItem.shootProjectile ++ Vec3 vec3 = this.getHandle().getUpVector(1.0F); ++ org.joml.Quaternionf quaternionf = new org.joml.Quaternionf().setAngleAxis((double)(yaw * (float) (Math.PI / 180.0)), vec3.x, vec3.y, vec3.z); ++ Vec3 vec32 = this.getHandle().getViewVector(1.0F); ++ org.joml.Vector3f vector3f = vec32.toVector3f().rotate(quaternionf); ++ ((FireworkRocketEntity) launch).shoot((double)vector3f.x(), (double)vector3f.y(), (double)vector3f.z(), net.minecraft.world.item.CrossbowItem.FIREWORK_POWER, 1.0F); ++ // Paper end + } + + Preconditions.checkArgument(launch != null, "Projectile (%s) not supported", projectile.getName()); +@@ -672,6 +697,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + if (velocity != null) { + ((T) launch.getBukkitEntity()).setVelocity(velocity); + } ++ // Paper start - launchProjectile consumer ++ if (function != null) { ++ function.accept((T) launch.getBukkitEntity()); ++ } ++ // Paper end - launchProjectile consumer + + world.addFreshEntity(launch); + return (T) launch.getBukkitEntity(); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java +index 70cbc6c668c60e9d608ca7013b72f9b916c05c2d..47633f05b4fab1dcabc2117e7645fe6d6949622a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java +@@ -20,13 +20,5 @@ public class CraftLlamaSpit extends AbstractProjectile implements LlamaSpit { + return "CraftLlamaSpit"; + } + +- @Override +- public ProjectileSource getShooter() { +- return (this.getHandle().getOwner() != null) ? (ProjectileSource) this.getHandle().getOwner().getBukkitEntity() : null; +- } +- +- @Override +- public void setShooter(ProjectileSource source) { +- this.getHandle().setOwner((source != null) ? ((CraftLivingEntity) source).getHandle() : null); +- } ++ // Paper - moved to AbstractProjectile + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java +index 696fdfa723aa896a67946f862d7c6890f7f7ab17..4f1fa7dec78970bdfc184d3c1f1632dc9d75a574 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java +@@ -10,20 +10,7 @@ public abstract class CraftProjectile extends AbstractProjectile implements Proj + super(server, entity); + } + +- @Override +- public ProjectileSource getShooter() { +- return this.getHandle().projectileSource; +- } +- +- @Override +- public void setShooter(ProjectileSource shooter) { +- if (shooter instanceof CraftLivingEntity) { +- this.getHandle().setOwner((LivingEntity) ((CraftLivingEntity) shooter).entity); +- } else { +- this.getHandle().setOwner(null); +- } +- this.getHandle().projectileSource = shooter; +- } ++ // Paper - moved to AbstractProjectile + + @Override + public net.minecraft.world.entity.projectile.Projectile getHandle() { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java +index d685d09cae5f862c0004f148298c800736d2139e..b3797a43eeee11cb7ae0774d61bd5f195d0aa3ad 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java +@@ -12,31 +12,56 @@ public class CraftShulkerBullet extends AbstractProjectile implements ShulkerBul + super(server, entity); + } + ++ // Paper - moved to AbstractProjectile ++ ++ @Override ++ public org.bukkit.entity.Entity getTarget() { ++ return this.getHandle().getTarget() != null ? this.getHandle().getTarget().getBukkitEntity() : null; ++ } ++ + @Override +- public ProjectileSource getShooter() { +- return this.getHandle().projectileSource; ++ public void setTarget(org.bukkit.entity.Entity target) { ++ Preconditions.checkState(!this.getHandle().generation, "Cannot set target during world generation"); ++ ++ this.getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle()); + } + + @Override +- public void setShooter(ProjectileSource shooter) { +- if (shooter instanceof Entity) { +- this.getHandle().setOwner(((CraftEntity) shooter).getHandle()); +- } else { +- this.getHandle().setOwner(null); ++ public org.bukkit.util.Vector getTargetDelta() { ++ net.minecraft.world.entity.projectile.ShulkerBullet bullet = this.getHandle(); ++ return new org.bukkit.util.Vector(bullet.targetDeltaX, bullet.targetDeltaY, bullet.targetDeltaZ); ++ } ++ ++ @Override ++ public void setTargetDelta(org.bukkit.util.Vector vector) { ++ net.minecraft.world.entity.projectile.ShulkerBullet bullet = this.getHandle(); ++ bullet.targetDeltaX = vector.getX(); ++ bullet.targetDeltaY = vector.getY(); ++ bullet.targetDeltaZ = vector.getZ(); ++ } ++ ++ @Override ++ public org.bukkit.block.BlockFace getCurrentMovementDirection() { ++ net.minecraft.core.Direction dir = this.getHandle().currentMoveDirection; ++ if (dir == null) { ++ return null; // random dir + } +- this.getHandle().projectileSource = shooter; ++ return org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(dir); + } + + @Override +- public org.bukkit.entity.Entity getTarget() { +- return this.getHandle().getTarget() != null ? this.getHandle().getTarget().getBukkitEntity() : null; ++ public void setCurrentMovementDirection(org.bukkit.block.BlockFace movementDirection) { ++ this.getHandle().currentMoveDirection = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(movementDirection); + } + + @Override +- public void setTarget(org.bukkit.entity.Entity target) { +- Preconditions.checkState(!this.getHandle().generation, "Cannot set target during world generation"); ++ public int getFlightSteps() { ++ return this.getHandle().flightSteps; ++ } + +- this.getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle()); ++ @Override ++ public void setFlightSteps(int steps) { ++ this.getHandle().flightSteps = steps; + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java +index d67a80161b3e7c1fe02a6ed9d341c00dc7c2847a..f6fa6f1ac50b757dd3bc9a8dee9f6085446182c8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java +@@ -36,11 +36,31 @@ public class CraftThrownPotion extends CraftThrowableProjectile implements Throw + @Override + public void setItem(ItemStack item) { + Preconditions.checkArgument(item != null, "ItemStack cannot be null"); +- Preconditions.checkArgument(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack material must be Material.LINGERING_POTION or Material.SPLASH_POTION but was Material.%s", item.getType()); ++ // Preconditions.checkArgument(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack material must be Material.LINGERING_POTION or Material.SPLASH_POTION but was Material.%s", item.getType()); // Paper - Projectile API ++ org.bukkit.inventory.meta.PotionMeta meta = (item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION) ? null : this.getPotionMeta(); // Paper - Projectile API + + this.getHandle().setItem(CraftItemStack.asNMSCopy(item)); ++ if (meta != null) this.setPotionMeta(meta); // Paper - Projectile API + } + ++ // Paper start - Projectile API ++ @Override ++ public org.bukkit.inventory.meta.PotionMeta getPotionMeta() { ++ return (org.bukkit.inventory.meta.PotionMeta) CraftItemStack.getItemMeta(this.getHandle().getItem(), org.bukkit.inventory.ItemType.SPLASH_POTION); ++ } ++ ++ @Override ++ public void setPotionMeta(org.bukkit.inventory.meta.PotionMeta meta) { ++ net.minecraft.world.item.ItemStack item = this.getHandle().getItem(); ++ CraftItemStack.applyMetaToItem(item, meta); ++ this.getHandle().setItem(item); // Reset item ++ } ++ ++ @Override ++ public void splash() { ++ this.getHandle().splash(null); ++ } ++ // Paper end + @Override + public net.minecraft.world.entity.projectile.ThrownPotion getHandle() { + return (net.minecraft.world.entity.projectile.ThrownPotion) this.entity; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java +index e374b9f40eddca13b30855d25a2030f8df98138f..4fc893378fb0568ddcffc7593d66df6bfe23f659 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java +@@ -53,5 +53,15 @@ public class CraftTrident extends CraftAbstractArrow implements Trident { + com.google.common.base.Preconditions.checkArgument(loyaltyLevel >= 0 && loyaltyLevel <= 127, "The loyalty level has to be between 0 and 127"); + this.getHandle().setLoyalty((byte) loyaltyLevel); + } ++ ++ @Override ++ public boolean hasDealtDamage() { ++ return this.getHandle().dealtDamage; ++ } ++ ++ @Override ++ public void setHasDealtDamage(boolean hasDealtDamage) { ++ this.getHandle().dealtDamage = hasDealtDamage; ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index a9ba62a9d605234d993b6e5330889795099af391..e0418c0c36aa99ea43dbf39fa176ddf8855e0568 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -841,19 +841,19 @@ public class CraftEventFactory { + /** + * PotionSplashEvent + */ +- public static PotionSplashEvent callPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, HitResult position, Map affectedEntities) { ++ public static PotionSplashEvent callPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult position, Map affectedEntities) { // Paper - nullable hitResult + ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity(); + + Block hitBlock = null; + BlockFace hitFace = null; +- if (position.getType() == HitResult.Type.BLOCK) { ++ if (position != null && position.getType() == HitResult.Type.BLOCK) { // Paper - nullable hitResult + BlockHitResult positionBlock = (BlockHitResult) position; + hitBlock = CraftBlock.at(potion.level(), positionBlock.getBlockPos()); + hitFace = CraftBlock.notchToBlockFace(positionBlock.getDirection()); + } + + org.bukkit.entity.Entity hitEntity = null; +- if (position.getType() == HitResult.Type.ENTITY) { ++ if (position != null && position.getType() == HitResult.Type.ENTITY) { // Paper - nullable hitResult + hitEntity = ((EntityHitResult) position).getEntity().getBukkitEntity(); + } + +@@ -862,20 +862,20 @@ public class CraftEventFactory { + return event; + } + +- public static LingeringPotionSplashEvent callLingeringPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, HitResult position, net.minecraft.world.entity.AreaEffectCloud cloud) { ++ public static LingeringPotionSplashEvent callLingeringPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult position, net.minecraft.world.entity.AreaEffectCloud cloud) { // Paper - nullable hitResult + ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity(); + AreaEffectCloud effectCloud = (AreaEffectCloud) cloud.getBukkitEntity(); + + Block hitBlock = null; + BlockFace hitFace = null; +- if (position.getType() == HitResult.Type.BLOCK) { ++ if (position != null && position.getType() == HitResult.Type.BLOCK) { // Paper + BlockHitResult positionBlock = (BlockHitResult) position; + hitBlock = CraftBlock.at(potion.level(), positionBlock.getBlockPos()); + hitFace = CraftBlock.notchToBlockFace(positionBlock.getDirection()); + } + + org.bukkit.entity.Entity hitEntity = null; +- if (position.getType() == HitResult.Type.ENTITY) { ++ if (position != null && position.getType() == HitResult.Type.ENTITY) { // Paper + hitEntity = ((EntityHitResult) position).getEntity().getBukkitEntity(); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 60062ea5b18b95a14c459f2f3a0743c1e1ac0f12..502be683e8b04a9966043c9bee9d9fe793b12ef5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -341,12 +341,23 @@ public final class CraftItemStack extends ItemStack { + public ItemMeta getItemMeta() { + return CraftItemStack.getItemMeta(this.handle); + } ++ // Paper start ++ public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { ++ final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); ++ ((CraftMetaItem) itemMeta).applyToItem(tag); ++ itemStack.applyComponents(tag.build()); ++ } + + public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item) { ++ return getItemMeta(item, null); ++ } ++ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType) { ++ // Paper end + if (!CraftItemStack.hasItemMeta(item)) { + return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item)); + } + ++ if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item); } // Paper + return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java +index 642f5bf75661eb485558bc227f668e84416f3b5f..76fd4d27730d9139caa67099a6757ea33d681be9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java ++++ b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java +@@ -56,7 +56,15 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { + + @Override + public T launchProjectile(Class projectile, Vector velocity) { ++ // Paper start - launchProjectile consumer ++ return this.launchProjectile(projectile, velocity, null); ++ } ++ ++ @Override ++ public T launchProjectile(Class projectile, Vector velocity, java.util.function.Consumer function) { ++ // Paper end - launchProjectile consumer + Preconditions.checkArgument(this.getBlock().getType() == Material.DISPENSER, "Block is no longer dispenser"); ++ + // Copied from BlockDispenser.dispense() + BlockSource sourceblock = new BlockSource((ServerLevel) this.dispenserBlock.getLevel(), this.dispenserBlock.getBlockPos(), this.dispenserBlock.getBlockState(), this.dispenserBlock); + // Copied from DispenseBehaviorProjectile +@@ -68,7 +76,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { + item = Items.SNOWBALL; + } else if (Egg.class.isAssignableFrom(projectile)) { + item = Items.EGG; +- } else if (EnderPearl.class.isAssignableFrom(projectile)) { ++ } else if (false && EnderPearl.class.isAssignableFrom(projectile)) { // Paper - more projectile API - disallow enderpearl, it is not a projectile item + item = Items.ENDER_PEARL; + } else if (ThrownExpBottle.class.isAssignableFrom(projectile)) { + item = Items.EXPERIENCE_BOTTLE; +@@ -83,20 +91,20 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { + item = Items.TIPPED_ARROW; + } else if (SpectralArrow.class.isAssignableFrom(projectile)) { + item = Items.SPECTRAL_ARROW; +- } else { ++ } else if (org.bukkit.entity.Arrow.class.isAssignableFrom(projectile)) { // Paper - more projectile API - disallow trident + item = Items.ARROW; + } + } else if (Fireball.class.isAssignableFrom(projectile)) { +- if (AbstractWindCharge.class.isAssignableFrom(projectile)) { ++ if (org.bukkit.entity.WindCharge.class.isAssignableFrom(projectile)) { // Paper - more projectile API - only allow wind charge not breeze wind charge + item = Items.WIND_CHARGE; +- } else { ++ } else if (org.bukkit.entity.SmallFireball.class.isAssignableFrom(projectile)) { // Paper - more projectile API - only allow firing fire charges. + item = Items.FIRE_CHARGE; + } + } else if (Firework.class.isAssignableFrom(projectile)) { + item = Items.FIREWORK_ROCKET; + } + +- Preconditions.checkArgument(item instanceof ProjectileItem, "Projectile not supported"); ++ Preconditions.checkArgument(item instanceof ProjectileItem, "Projectile '%s' not supported", projectile.getSimpleName()); // Paper - more projectile API - include simple name in exception + + ItemStack itemstack = new ItemStack(item); + ProjectileItem projectileItem = (ProjectileItem) item; +@@ -105,7 +113,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { + Position iposition = dispenseConfig.positionFunction().getDispensePosition(sourceblock, enumdirection); + net.minecraft.world.entity.projectile.Projectile launch = projectileItem.asProjectile(world, iposition, itemstack, enumdirection); + +- if (Fireball.class.isAssignableFrom(projectile)) { ++ if (false && Fireball.class.isAssignableFrom(projectile)) { // Paper - more project API - dispensers cannot launch anything but fire charges. + AbstractHurtingProjectile customFireball = null; + if (WitherSkull.class.isAssignableFrom(projectile)) { + launch = customFireball = EntityType.WITHER_SKULL.create(world, EntitySpawnReason.TRIGGERED); +@@ -130,7 +138,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { + } + } + +- if (launch instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) { ++ if (false && launch instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) { // Paper - more projectile API - this is set by the respective ArrowItem when constructing the projectile + arrow.pickup = net.minecraft.world.entity.projectile.AbstractArrow.Pickup.ALLOWED; + } + launch.projectileSource = this; +@@ -139,6 +147,11 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { + if (velocity != null) { + ((T) launch.getBukkitEntity()).setVelocity(velocity); + } ++ // Paper start ++ if (function != null) { ++ function.accept((T) launch.getBukkitEntity()); ++ } ++ // Paper end + + world.addFreshEntity(launch); + return (T) launch.getBukkitEntity(); diff --git a/patches/server/0670-Fix-swamp-hut-cat-generation-deadlock.patch b/patches/server/0670-Fix-swamp-hut-cat-generation-deadlock.patch new file mode 100644 index 0000000000..24bfbc0dc7 --- /dev/null +++ b/patches/server/0670-Fix-swamp-hut-cat-generation-deadlock.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 12 Mar 2022 06:31:13 -0800 +Subject: [PATCH] Fix swamp hut cat generation deadlock + +The worldgen thread will attempt to get structure references +via the world's getChunkAt method, which is fine if the gen is +not cancelled - but if the chunk was unloaded, the call will block +indefinitely. Instead of using the world state, we use the already +supplied ServerLevelAccessor which will always have the chunk available. + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java +index f3a991aa878f3b29fdc525ecdde6766efb5e129c..5a86530c65d7d83e4608600a04ffd931bf59dc4a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java +@@ -366,7 +366,7 @@ public class Cat extends TamableAnimal implements VariantHolder startsForStructure(ChunkPos pos, Predicate predicate) { +- Map map = this.level.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); ++ // Paper start - Fix swamp hut cat generation deadlock ++ return this.startsForStructure(pos, predicate, null); ++ } ++ public List startsForStructure(ChunkPos pos, Predicate predicate, @Nullable ServerLevelAccessor levelAccessor) { ++ Map map = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); ++ // Paper end - Fix swamp hut cat generation deadlock + Builder builder = ImmutableList.builder(); + + for (Entry entry : map.entrySet()) { +@@ -116,10 +121,20 @@ public class StructureManager { + } + + public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate) { ++ // Paper start - Fix swamp hut cat generation deadlock ++ return this.getStructureWithPieceAt(pos, predicate, null); ++ } ++ ++ public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey tag, @Nullable ServerLevelAccessor levelAccessor) { ++ return this.getStructureWithPieceAt(pos, structure -> structure.is(tag), levelAccessor); ++ } ++ ++ public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate, @Nullable ServerLevelAccessor levelAccessor) { ++ // Paper end - Fix swamp hut cat generation deadlock + Registry registry = this.registryAccess().lookupOrThrow(Registries.STRUCTURE); + + for (StructureStart structureStart : this.startsForStructure( +- new ChunkPos(pos), structure -> registry.get(registry.getId(structure)).map(predicate::test).orElse(false) ++ new ChunkPos(pos), structure -> registry.get(registry.getId(structure)).map(predicate::test).orElse(false), levelAccessor // Paper - Fix swamp hut cat generation deadlock + )) { + if (this.structureHasPieceAt(pos, structureStart)) { + return structureStart; diff --git a/patches/server/0670-More-Projectile-API.patch b/patches/server/0670-More-Projectile-API.patch deleted file mode 100644 index 9f9c1e0dd4..0000000000 --- a/patches/server/0670-More-Projectile-API.patch +++ /dev/null @@ -1,932 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Tue, 22 Jun 2021 23:41:11 -0400 -Subject: [PATCH] More Projectile API - -== AT == -public net.minecraft.world.entity.projectile.FishingHook timeUntilLured -public net.minecraft.world.entity.projectile.FishingHook fishAngle -public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaX -public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaY -public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaZ -public net.minecraft.world.entity.projectile.ShulkerBullet currentMoveDirection -public net.minecraft.world.entity.projectile.ShulkerBullet flightSteps -public net.minecraft.world.entity.projectile.AbstractArrow soundEvent -public net.minecraft.world.entity.projectile.AbstractArrow setPickupItemStack(Lnet/minecraft/world/item/ItemStack;)V -public net.minecraft.world.entity.projectile.ThrownTrident dealtDamage -public net.minecraft.world.entity.projectile.Arrow NO_EFFECT_COLOR -public net.minecraft.world.entity.projectile.Projectile hasBeenShot -public net.minecraft.world.entity.projectile.Projectile leftOwner -public net.minecraft.world.entity.projectile.Projectile ownerUUID -public net.minecraft.world.entity.projectile.Projectile preOnHit(Lnet/minecraft/world/phys/HitResult;)V -public net.minecraft.world.entity.projectile.Projectile canHitEntity(Lnet/minecraft/world/entity/Entity;)Z -public net.minecraft.world.entity.projectile.FireworkRocketEntity getDefaultItem()Lnet/minecraft/world/item/ItemStack; -public net.minecraft.world.item.CrossbowItem FIREWORK_POWER - -Co-authored-by: Nassim Jahnke -Co-authored-by: SoSeDiK -Co-authored-by: MelnCat -Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -index 536196a740f607adda2a5ae7f644981ac26bef98..1f95234c0a1457050574aa0f6c4b2a8c91b1f272 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -@@ -419,13 +419,18 @@ public class FishingHook extends Projectile { - } - } else { - // CraftBukkit start - logic to modify fishing wait time -- this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime); -- this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop -+ this.resetTimeUntilLured(); // Paper - more projectile api - extract time until lured reset logic - // CraftBukkit end - } - } - - } -+ // Paper start - more projectile api - extract time until lured reset logic -+ public void resetTimeUntilLured() { -+ this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime); -+ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop -+ } -+ // Paper end - more projectile api - extract time until lured reset logic - - public boolean calculateOpenWater(BlockPos pos) { - FishingHook.OpenWaterType entityfishinghook_waterposition = FishingHook.OpenWaterType.INVALID; -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 09d1131c7f2b32b6c032341a60521608b098c109..824090367e833c57a22c1017981f0508b28a35d2 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -288,7 +288,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { - } - - // CraftBukkit start - call projectile hit event -- protected ProjectileDeflection preHitTargetOrDeflectSelf(HitResult movingobjectposition) { -+ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult movingobjectposition) { // Paper - protected -> public - org.bukkit.event.entity.ProjectileHitEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this, movingobjectposition); - this.hitCancelled = event != null && event.isCancelled(); - if (movingobjectposition.getType() == HitResult.Type.BLOCK || !this.hitCancelled) { -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -index d6ac07d9d5ee0430a1d91b7084b378aac1d047e5..a486466040a646b8a5a5ff2430cdd25b95b7e20f 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -@@ -103,8 +103,12 @@ public class ThrownPotion extends ThrowableItemProjectile { - @Override - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); -+ // Paper start - More projectile API -+ this.splash(hitResult); -+ } -+ public void splash(@Nullable HitResult hitResult) { -+ // Paper end - More projectile API - Level world = this.level(); -- - if (world instanceof ServerLevel worldserver) { - ItemStack itemstack = this.getItem(); - PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); -@@ -116,7 +120,7 @@ public class ThrownPotion extends ThrowableItemProjectile { - if (this.isLingering()) { - showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - } else { -- showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper -+ showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult != null && hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API - } - } - -@@ -178,7 +182,7 @@ public class ThrownPotion extends ThrowableItemProjectile { - - } - -- private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events -+ private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events & More projectile API - AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); - List list = worldserver.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb); - Map affected = new HashMap(); // CraftBukkit -@@ -256,7 +260,7 @@ public class ThrownPotion extends ThrowableItemProjectile { - - } - -- private boolean makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition -+ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API - AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); - Entity entity = this.getOwner(); - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java -index 91c2d0b40d3fca86938cd454e1415a4eea3df7c7..de4fb2654c7895cfd83ad694455ee56cb708c2f2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java -@@ -17,4 +17,65 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti - @Override - public void setBounce(boolean doesBounce) {} - -+ // Paper start - More projectile API -+ @Override -+ public boolean hasLeftShooter() { -+ return this.getHandle().leftOwner; -+ } -+ -+ @Override -+ public void setHasLeftShooter(boolean leftShooter) { -+ this.getHandle().leftOwner = leftShooter; -+ } -+ -+ @Override -+ public boolean hasBeenShot() { -+ return this.getHandle().hasBeenShot; -+ } -+ -+ @Override -+ public void setHasBeenShot(boolean beenShot) { -+ this.getHandle().hasBeenShot = beenShot; -+ } -+ -+ @Override -+ public boolean canHitEntity(org.bukkit.entity.Entity entity) { -+ return this.getHandle().canHitEntity(((CraftEntity) entity).getHandle()); -+ } -+ -+ @Override -+ public void hitEntity(org.bukkit.entity.Entity entity) { -+ this.getHandle().preHitTargetOrDeflectSelf(new net.minecraft.world.phys.EntityHitResult(((CraftEntity) entity).getHandle())); -+ } -+ -+ @Override -+ public void hitEntity(org.bukkit.entity.Entity entity, org.bukkit.util.Vector vector) { -+ this.getHandle().preHitTargetOrDeflectSelf(new net.minecraft.world.phys.EntityHitResult(((CraftEntity) entity).getHandle(), new net.minecraft.world.phys.Vec3(vector.getX(), vector.getY(), vector.getZ()))); -+ } -+ -+ @Override -+ public net.minecraft.world.entity.projectile.Projectile getHandle() { -+ return (net.minecraft.world.entity.projectile.Projectile) entity; -+ } -+ -+ @Override -+ public final org.bukkit.projectiles.ProjectileSource getShooter() { -+ return this.getHandle().projectileSource; -+ } -+ -+ @Override -+ public final void setShooter(org.bukkit.projectiles.ProjectileSource shooter) { -+ if (shooter instanceof CraftEntity craftEntity) { -+ this.getHandle().setOwner(craftEntity.getHandle()); -+ } else { -+ this.getHandle().setOwner(null); -+ } -+ this.getHandle().projectileSource = shooter; -+ } -+ -+ @Override -+ public java.util.UUID getOwnerUniqueId() { -+ return this.getHandle().ownerUUID; -+ } -+ // Paper end - More projectile API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java -index 0f85c1f991469b277bba8b40b087f7224b4b3a85..1f30109abd86b76af343eb5eb75ec3db83ef9417 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java -@@ -59,20 +59,7 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr - this.getHandle().setCritArrow(critical); - } - -- @Override -- public ProjectileSource getShooter() { -- return this.getHandle().projectileSource; -- } -- -- @Override -- public void setShooter(ProjectileSource shooter) { -- if (shooter instanceof Entity) { -- this.getHandle().setOwner(((CraftEntity) shooter).getHandle()); -- } else { -- this.getHandle().setOwner(null); -- } -- this.getHandle().projectileSource = shooter; -- } -+ // Paper - moved to AbstractProjectile - - @Override - public boolean isInBlock() { -@@ -133,6 +120,7 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr - - @Override - public ItemStack getWeapon() { -+ if (this.getHandle().getWeaponItem() == null) return null; // Paper - fix NPE - return CraftItemStack.asBukkitCopy(this.getHandle().getWeaponItem()); - } - -@@ -152,4 +140,37 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr - public String toString() { - return "CraftArrow"; - } -+ -+ // Paper start -+ @Override -+ public CraftItemStack getItemStack() { -+ return CraftItemStack.asCraftMirror(this.getHandle().getPickupItem()); -+ } -+ -+ @Override -+ public void setItemStack(final ItemStack stack) { -+ Preconditions.checkArgument(stack != null, "ItemStack cannot be null"); -+ this.getHandle().setPickupItemStack(CraftItemStack.asNMSCopy(stack)); -+ } -+ -+ @Override -+ public void setLifetimeTicks(int ticks) { -+ this.getHandle().life = ticks; -+ } -+ -+ @Override -+ public int getLifetimeTicks() { -+ return this.getHandle().life; -+ } -+ -+ @Override -+ public org.bukkit.Sound getHitSound() { -+ return org.bukkit.craftbukkit.CraftSound.minecraftToBukkit(this.getHandle().soundEvent); -+ } -+ -+ @Override -+ public void setHitSound(org.bukkit.Sound sound) { -+ this.getHandle().setSoundEvent(org.bukkit.craftbukkit.CraftSound.bukkitToMinecraft(sound)); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -index 6591513bb62226b6f85fd2ef9f6ebe376f0f7362..f9c113dc018702159345240d6d0de85767afa0c3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -@@ -125,7 +125,7 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud - - @Override - public Color getColor() { -- return Color.fromRGB(this.getHandle().potionContents.getColor()); -+ return Color.fromRGB(this.getHandle().potionContents.getColor() & 0x00FFFFFF); // Paper - skip alpha channel - } - - @Override -@@ -143,7 +143,7 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud - this.removeCustomEffect(effect.getType()); - } - this.getHandle().addEffect(CraftPotionUtil.fromBukkit(effect)); -- this.getHandle().updateColor(); -+ // this.getHandle().updateColor(); // Paper - already done above - return true; - } - -@@ -151,7 +151,7 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud - public void clearCustomEffects() { - PotionContents old = this.getHandle().potionContents; - this.getHandle().setPotionContents(new PotionContents(old.potion(), old.customColor(), List.of(), old.customName())); -- this.getHandle().updateColor(); -+ // this.getHandle().updateColor(); // Paper - already done above - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java -index 199d5836dc787cca54c6b653a4e67573f2f758a2..15d50a284cafc2eb59239ca00926836526f09e06 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java -@@ -43,7 +43,7 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow { - this.removeCustomEffect(effect.getType()); - } - this.getHandle().addEffect(CraftPotionUtil.fromBukkit(effect)); -- this.getHandle().updateColor(); -+ // this.getHandle().updateColor(); // Paper - already done above - return true; - } - -@@ -51,7 +51,7 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow { - public void clearCustomEffects() { - PotionContents old = this.getHandle().getPotionContents(); - this.getHandle().setPotionContents(new PotionContents(old.potion(), old.customColor(), List.of(), old.customName())); -- this.getHandle().updateColor(); -+ // this.getHandle().updateColor(); // Paper - already done above - } - - @Override -@@ -117,16 +117,17 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow { - - @Override - public void setColor(Color color) { -- int colorRGB = (color == null) ? -1 : color.asRGB(); -+ int colorRGB = (color == null) ? net.minecraft.world.entity.projectile.Arrow.NO_EFFECT_COLOR : color.asARGB(); // Paper - PotionContents old = this.getHandle().getPotionContents(); - this.getHandle().setPotionContents(new PotionContents(old.potion(), Optional.of(colorRGB), old.customEffects(), old.customName())); - } - - @Override - public Color getColor() { -- if (this.getHandle().getColor() <= -1) { -+ int color = this.getHandle().getColor(); // Paper -+ if (color == net.minecraft.world.entity.projectile.Arrow.NO_EFFECT_COLOR) { // Paper - return null; - } -- return Color.fromRGB(this.getHandle().getColor()); -+ return Color.fromARGB(color); // Paper - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -index b79e72a77178f755957ef391b6444a357bdefbd0..39ea25d2145acaa7c7b458800adc674a3e73e7c1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -442,7 +442,7 @@ public final class CraftEntityTypes { - BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z()); - return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly - })); -- register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), net.minecraft.world.item.ItemStack.EMPTY))); -+ register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), FireworkRocketEntity.getDefaultItem()))); // Paper - pass correct default to rocket for data storage - register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null))); - register(new EntityTypeData<>(EntityType.COMMAND_BLOCK_MINECART, CommandMinecart.class, CraftMinecartCommand::new, createMinecart(net.minecraft.world.entity.EntityType.COMMAND_BLOCK_MINECART))); - register(new EntityTypeData<>(EntityType.MINECART, RideableMinecart.class, CraftMinecartRideable::new, createMinecart(net.minecraft.world.entity.EntityType.MINECART))); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java -index 1b084d63bdbb24dad45d28eed1693eb6e26e24dc..43d7bea201a52cfeacf60c75caa28dfd2c4ff164 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java -@@ -34,20 +34,7 @@ public class CraftFireball extends AbstractProjectile implements Fireball { - this.getHandle().bukkitYield = yield; - } - -- @Override -- public ProjectileSource getShooter() { -- return this.getHandle().projectileSource; -- } -- -- @Override -- public void setShooter(ProjectileSource shooter) { -- if (shooter instanceof CraftLivingEntity) { -- this.getHandle().setOwner(((CraftLivingEntity) shooter).getHandle()); -- } else { -- this.getHandle().setOwner(null); -- } -- this.getHandle().projectileSource = shooter; -- } -+ // Paper - moved to AbstractProjectile - - @Override - public Vector getDirection() { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java -index c9e15a9d82dee935293b2e7e233f5b9b2d822448..2d54cf6f3d9696c55335f0a2057025e2034d4e13 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java -@@ -15,24 +15,26 @@ import org.bukkit.inventory.meta.FireworkMeta; - public class CraftFirework extends CraftProjectile implements Firework { - - private final Random random = new Random(); -- private final CraftItemStack item; -+ //private CraftItemStack item; // Paper - Remove usage, not accurate representation of current item. - - public CraftFirework(CraftServer server, FireworkRocketEntity entity) { - super(server, entity); - -- ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM); -- -- if (item.isEmpty()) { -- item = new ItemStack(Items.FIREWORK_ROCKET); -- this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); -- } -- -- this.item = CraftItemStack.asCraftMirror(item); -- -- // Ensure the item is a firework... -- if (this.item.getType() != Material.FIREWORK_ROCKET) { -- this.item.setType(Material.FIREWORK_ROCKET); -- } -+ // Paper start - Expose firework item directly -+// ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM); -+// -+// if (item.isEmpty()) { -+// item = new ItemStack(Items.FIREWORK_ROCKET); -+// this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); -+// } -+// -+// this.item = CraftItemStack.asCraftMirror(item); -+// -+// // Ensure the item is a firework... -+// if (this.item.getType() != Material.FIREWORK_ROCKET) { -+// this.item.setType(Material.FIREWORK_ROCKET); -+// } -+ // Paper end - Expose firework item directly - } - - @Override -@@ -47,12 +49,12 @@ public class CraftFirework extends CraftProjectile implements Firework { - - @Override - public FireworkMeta getFireworkMeta() { -- return (FireworkMeta) this.item.getItemMeta(); -+ return (FireworkMeta) CraftItemStack.getItemMeta(this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM), org.bukkit.inventory.ItemType.FIREWORK_ROCKET); // Paper - Expose firework item directly - } - - @Override - public void setFireworkMeta(FireworkMeta meta) { -- this.item.setItemMeta(meta); -+ applyFireworkEffect(meta); // Paper - Expose firework item directly - - // Copied from EntityFireworks constructor, update firework lifetime/power - this.getHandle().lifetime = 10 * (1 + meta.getPower()) + this.random.nextInt(6) + this.random.nextInt(7); -@@ -136,4 +138,46 @@ public class CraftFirework extends CraftProjectile implements Firework { - return getHandle().spawningEntity; - } - // Paper end -+ // Paper start - Expose firework item directly + manually setting flight -+ @Override -+ public org.bukkit.inventory.ItemStack getItem() { -+ return CraftItemStack.asBukkitCopy(this.getHandle().getItem()); -+ } -+ -+ @Override -+ public void setItem(org.bukkit.inventory.ItemStack itemStack) { -+ FireworkMeta meta = getFireworkMeta(); -+ ItemStack nmsItem = itemStack == null ? FireworkRocketEntity.getDefaultItem() : CraftItemStack.asNMSCopy(itemStack); -+ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, nmsItem); -+ -+ applyFireworkEffect(meta); -+ } -+ -+ @Override -+ public int getTicksFlown() { -+ return this.getHandle().life; -+ } -+ -+ @Override -+ public void setTicksFlown(int ticks) { -+ this.getHandle().life = ticks; -+ } -+ -+ @Override -+ public int getTicksToDetonate() { -+ return this.getHandle().lifetime; -+ } -+ -+ @Override -+ public void setTicksToDetonate(int ticks) { -+ this.getHandle().lifetime = ticks; -+ } -+ -+ void applyFireworkEffect(FireworkMeta meta) { -+ ItemStack item = this.getHandle().getItem(); -+ CraftItemStack.applyMetaToItem(item, meta); -+ -+ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); -+ } -+ // Paper end - Expose firework item directly + manually setting flight - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java -index 6e2f91423371ead9890095cf4b1e2299c4dcba28..9d8f4b7176e60180565e3134a14ecf19060f2621 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java -@@ -196,4 +196,42 @@ public class CraftFishHook extends CraftProjectile implements FishHook { - public HookState getState() { - return HookState.values()[this.getHandle().currentState.ordinal()]; - } -+ // Paper start - More FishHook API -+ @Override -+ public int getWaitTime() { -+ return this.getHandle().timeUntilLured; -+ } -+ -+ @Override -+ public void setWaitTime(int ticks) { -+ this.getHandle().timeUntilLured = ticks; -+ } -+ -+ @Override -+ public int getTimeUntilBite() { -+ return this.getHandle().timeUntilHooked; -+ } -+ -+ @Override -+ public void setTimeUntilBite(final int ticks) { -+ com.google.common.base.Preconditions.checkArgument(ticks >= 1, "Cannot set time until bite to less than 1 (%s<1)", ticks); -+ final FishingHook hook = this.getHandle(); -+ -+ // Reset the fish angle hook only when this call "enters" the fish into the lure stage. -+ final boolean alreadyInLuringPhase = hook.timeUntilHooked > 0 && hook.timeUntilLured <= 0; -+ if (!alreadyInLuringPhase) { -+ hook.fishAngle = net.minecraft.util.Mth.nextFloat(hook.random, hook.minLureAngle, hook.maxLureAngle); -+ hook.timeUntilLured = 0; -+ } -+ -+ hook.timeUntilHooked = ticks; -+ } -+ -+ @Override -+ public void resetFishingState() { -+ final FishingHook hook = this.getHandle(); -+ hook.resetTimeUntilLured(); -+ hook.timeUntilHooked = 0; // Reset time until hooked, will be repopulated once lured time is ticked down. -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index e148239d4930e5cbb000beed4de386f992f28d88..14b4c3835388d957653ba34444968bb718ce7f68 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -579,8 +579,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - } - - @Override -- @SuppressWarnings("unchecked") - public T launchProjectile(Class projectile, Vector velocity) { -+ // Paper start - launchProjectile consumer -+ return this.launchProjectile(projectile, velocity, null); -+ } -+ -+ @Override -+ @SuppressWarnings("unchecked") -+ public T launchProjectile(Class projectile, Vector velocity, java.util.function.Consumer function) { -+ // Paper end - launchProjectile consumer - Preconditions.checkState(!this.getHandle().generation, "Cannot launch projectile during world generation"); - - net.minecraft.world.level.Level world = ((CraftWorld) this.getWorld()).getHandle(); -@@ -606,7 +613,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - } else { - launch = new net.minecraft.world.entity.projectile.Arrow(world, this.getHandle(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.ARROW), null); - } -- ((net.minecraft.world.entity.projectile.AbstractArrow) launch).shootFromRotation(this.getHandle(), this.getHandle().getXRot(), this.getHandle().getYRot(), 0.0F, 3.0F, 1.0F); // ItemBow -+ ((net.minecraft.world.entity.projectile.AbstractArrow) launch).shootFromRotation(this.getHandle(), this.getHandle().getXRot(), this.getHandle().getYRot(), 0.0F, Trident.class.isAssignableFrom(projectile) ? net.minecraft.world.item.TridentItem.SHOOT_POWER : 3.0F, 1.0F); // ItemBow // Paper - see TridentItem - } else if (ThrownPotion.class.isAssignableFrom(projectile)) { - if (LingeringPotion.class.isAssignableFrom(projectile)) { - launch = new net.minecraft.world.entity.projectile.ThrownPotion(world, this.getHandle(), new net.minecraft.world.item.ItemStack(Items.LINGERING_POTION)); -@@ -663,8 +670,26 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - } else if (Firework.class.isAssignableFrom(projectile)) { - Location location = this.getEyeLocation(); - -- launch = new FireworkRocketEntity(world, net.minecraft.world.item.ItemStack.EMPTY, this.getHandle()); -- launch.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); -+ // Paper start - see CrossbowItem -+ launch = new FireworkRocketEntity(world, FireworkRocketEntity.getDefaultItem(), this.getHandle(), location.getX(), location.getY() - 0.15F, location.getZ(), true); // Paper - pass correct default to rocket for data storage & see CrossbowItem for regular launch without elytra boost -+ -+ // Lifted from net.minecraft.world.item.ProjectileWeaponItem.shoot -+ float f2 = /* net.minecraft.world.item.enchantment.EnchantmentHelper.processProjectileSpread((ServerLevel) world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.CROSSBOW), this.getHandle(), 0.0F); */ 0; // Just shortcut this to 0, no need to do any calculations on a non existing stack -+ int projectileSize = 1; -+ int i = 0; -+ -+ float f3 = projectileSize == 1 ? 0.0F : 2.0F * f2 / (float) (projectileSize - 1); -+ float f4 = (float) ((projectileSize - 1) % 2) * f3 / 2.0F; -+ float f5 = 1.0F; -+ float yaw = f4 + f5 * (float) ((i + 1) / 2) * f3; -+ -+ // Lifted from net.minecraft.world.item.CrossbowItem.shootProjectile -+ Vec3 vec3 = this.getHandle().getUpVector(1.0F); -+ org.joml.Quaternionf quaternionf = new org.joml.Quaternionf().setAngleAxis((double)(yaw * (float) (Math.PI / 180.0)), vec3.x, vec3.y, vec3.z); -+ Vec3 vec32 = this.getHandle().getViewVector(1.0F); -+ org.joml.Vector3f vector3f = vec32.toVector3f().rotate(quaternionf); -+ ((FireworkRocketEntity) launch).shoot((double)vector3f.x(), (double)vector3f.y(), (double)vector3f.z(), net.minecraft.world.item.CrossbowItem.FIREWORK_POWER, 1.0F); -+ // Paper end - } - - Preconditions.checkArgument(launch != null, "Projectile (%s) not supported", projectile.getName()); -@@ -672,6 +697,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - if (velocity != null) { - ((T) launch.getBukkitEntity()).setVelocity(velocity); - } -+ // Paper start - launchProjectile consumer -+ if (function != null) { -+ function.accept((T) launch.getBukkitEntity()); -+ } -+ // Paper end - launchProjectile consumer - - world.addFreshEntity(launch); - return (T) launch.getBukkitEntity(); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java -index 70cbc6c668c60e9d608ca7013b72f9b916c05c2d..47633f05b4fab1dcabc2117e7645fe6d6949622a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java -@@ -20,13 +20,5 @@ public class CraftLlamaSpit extends AbstractProjectile implements LlamaSpit { - return "CraftLlamaSpit"; - } - -- @Override -- public ProjectileSource getShooter() { -- return (this.getHandle().getOwner() != null) ? (ProjectileSource) this.getHandle().getOwner().getBukkitEntity() : null; -- } -- -- @Override -- public void setShooter(ProjectileSource source) { -- this.getHandle().setOwner((source != null) ? ((CraftLivingEntity) source).getHandle() : null); -- } -+ // Paper - moved to AbstractProjectile - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java -index 696fdfa723aa896a67946f862d7c6890f7f7ab17..4f1fa7dec78970bdfc184d3c1f1632dc9d75a574 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java -@@ -10,20 +10,7 @@ public abstract class CraftProjectile extends AbstractProjectile implements Proj - super(server, entity); - } - -- @Override -- public ProjectileSource getShooter() { -- return this.getHandle().projectileSource; -- } -- -- @Override -- public void setShooter(ProjectileSource shooter) { -- if (shooter instanceof CraftLivingEntity) { -- this.getHandle().setOwner((LivingEntity) ((CraftLivingEntity) shooter).entity); -- } else { -- this.getHandle().setOwner(null); -- } -- this.getHandle().projectileSource = shooter; -- } -+ // Paper - moved to AbstractProjectile - - @Override - public net.minecraft.world.entity.projectile.Projectile getHandle() { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java -index d685d09cae5f862c0004f148298c800736d2139e..b3797a43eeee11cb7ae0774d61bd5f195d0aa3ad 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java -@@ -12,31 +12,56 @@ public class CraftShulkerBullet extends AbstractProjectile implements ShulkerBul - super(server, entity); - } - -+ // Paper - moved to AbstractProjectile -+ -+ @Override -+ public org.bukkit.entity.Entity getTarget() { -+ return this.getHandle().getTarget() != null ? this.getHandle().getTarget().getBukkitEntity() : null; -+ } -+ - @Override -- public ProjectileSource getShooter() { -- return this.getHandle().projectileSource; -+ public void setTarget(org.bukkit.entity.Entity target) { -+ Preconditions.checkState(!this.getHandle().generation, "Cannot set target during world generation"); -+ -+ this.getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle()); - } - - @Override -- public void setShooter(ProjectileSource shooter) { -- if (shooter instanceof Entity) { -- this.getHandle().setOwner(((CraftEntity) shooter).getHandle()); -- } else { -- this.getHandle().setOwner(null); -+ public org.bukkit.util.Vector getTargetDelta() { -+ net.minecraft.world.entity.projectile.ShulkerBullet bullet = this.getHandle(); -+ return new org.bukkit.util.Vector(bullet.targetDeltaX, bullet.targetDeltaY, bullet.targetDeltaZ); -+ } -+ -+ @Override -+ public void setTargetDelta(org.bukkit.util.Vector vector) { -+ net.minecraft.world.entity.projectile.ShulkerBullet bullet = this.getHandle(); -+ bullet.targetDeltaX = vector.getX(); -+ bullet.targetDeltaY = vector.getY(); -+ bullet.targetDeltaZ = vector.getZ(); -+ } -+ -+ @Override -+ public org.bukkit.block.BlockFace getCurrentMovementDirection() { -+ net.minecraft.core.Direction dir = this.getHandle().currentMoveDirection; -+ if (dir == null) { -+ return null; // random dir - } -- this.getHandle().projectileSource = shooter; -+ return org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(dir); - } - - @Override -- public org.bukkit.entity.Entity getTarget() { -- return this.getHandle().getTarget() != null ? this.getHandle().getTarget().getBukkitEntity() : null; -+ public void setCurrentMovementDirection(org.bukkit.block.BlockFace movementDirection) { -+ this.getHandle().currentMoveDirection = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(movementDirection); - } - - @Override -- public void setTarget(org.bukkit.entity.Entity target) { -- Preconditions.checkState(!this.getHandle().generation, "Cannot set target during world generation"); -+ public int getFlightSteps() { -+ return this.getHandle().flightSteps; -+ } - -- this.getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle()); -+ @Override -+ public void setFlightSteps(int steps) { -+ this.getHandle().flightSteps = steps; - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java -index d67a80161b3e7c1fe02a6ed9d341c00dc7c2847a..f6fa6f1ac50b757dd3bc9a8dee9f6085446182c8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java -@@ -36,11 +36,31 @@ public class CraftThrownPotion extends CraftThrowableProjectile implements Throw - @Override - public void setItem(ItemStack item) { - Preconditions.checkArgument(item != null, "ItemStack cannot be null"); -- Preconditions.checkArgument(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack material must be Material.LINGERING_POTION or Material.SPLASH_POTION but was Material.%s", item.getType()); -+ // Preconditions.checkArgument(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack material must be Material.LINGERING_POTION or Material.SPLASH_POTION but was Material.%s", item.getType()); // Paper - Projectile API -+ org.bukkit.inventory.meta.PotionMeta meta = (item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION) ? null : this.getPotionMeta(); // Paper - Projectile API - - this.getHandle().setItem(CraftItemStack.asNMSCopy(item)); -+ if (meta != null) this.setPotionMeta(meta); // Paper - Projectile API - } - -+ // Paper start - Projectile API -+ @Override -+ public org.bukkit.inventory.meta.PotionMeta getPotionMeta() { -+ return (org.bukkit.inventory.meta.PotionMeta) CraftItemStack.getItemMeta(this.getHandle().getItem(), org.bukkit.inventory.ItemType.SPLASH_POTION); -+ } -+ -+ @Override -+ public void setPotionMeta(org.bukkit.inventory.meta.PotionMeta meta) { -+ net.minecraft.world.item.ItemStack item = this.getHandle().getItem(); -+ CraftItemStack.applyMetaToItem(item, meta); -+ this.getHandle().setItem(item); // Reset item -+ } -+ -+ @Override -+ public void splash() { -+ this.getHandle().splash(null); -+ } -+ // Paper end - @Override - public net.minecraft.world.entity.projectile.ThrownPotion getHandle() { - return (net.minecraft.world.entity.projectile.ThrownPotion) this.entity; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java -index e374b9f40eddca13b30855d25a2030f8df98138f..4fc893378fb0568ddcffc7593d66df6bfe23f659 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java -@@ -53,5 +53,15 @@ public class CraftTrident extends CraftAbstractArrow implements Trident { - com.google.common.base.Preconditions.checkArgument(loyaltyLevel >= 0 && loyaltyLevel <= 127, "The loyalty level has to be between 0 and 127"); - this.getHandle().setLoyalty((byte) loyaltyLevel); - } -+ -+ @Override -+ public boolean hasDealtDamage() { -+ return this.getHandle().dealtDamage; -+ } -+ -+ @Override -+ public void setHasDealtDamage(boolean hasDealtDamage) { -+ this.getHandle().dealtDamage = hasDealtDamage; -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index a9ba62a9d605234d993b6e5330889795099af391..e0418c0c36aa99ea43dbf39fa176ddf8855e0568 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -841,19 +841,19 @@ public class CraftEventFactory { - /** - * PotionSplashEvent - */ -- public static PotionSplashEvent callPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, HitResult position, Map affectedEntities) { -+ public static PotionSplashEvent callPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult position, Map affectedEntities) { // Paper - nullable hitResult - ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity(); - - Block hitBlock = null; - BlockFace hitFace = null; -- if (position.getType() == HitResult.Type.BLOCK) { -+ if (position != null && position.getType() == HitResult.Type.BLOCK) { // Paper - nullable hitResult - BlockHitResult positionBlock = (BlockHitResult) position; - hitBlock = CraftBlock.at(potion.level(), positionBlock.getBlockPos()); - hitFace = CraftBlock.notchToBlockFace(positionBlock.getDirection()); - } - - org.bukkit.entity.Entity hitEntity = null; -- if (position.getType() == HitResult.Type.ENTITY) { -+ if (position != null && position.getType() == HitResult.Type.ENTITY) { // Paper - nullable hitResult - hitEntity = ((EntityHitResult) position).getEntity().getBukkitEntity(); - } - -@@ -862,20 +862,20 @@ public class CraftEventFactory { - return event; - } - -- public static LingeringPotionSplashEvent callLingeringPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, HitResult position, net.minecraft.world.entity.AreaEffectCloud cloud) { -+ public static LingeringPotionSplashEvent callLingeringPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult position, net.minecraft.world.entity.AreaEffectCloud cloud) { // Paper - nullable hitResult - ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity(); - AreaEffectCloud effectCloud = (AreaEffectCloud) cloud.getBukkitEntity(); - - Block hitBlock = null; - BlockFace hitFace = null; -- if (position.getType() == HitResult.Type.BLOCK) { -+ if (position != null && position.getType() == HitResult.Type.BLOCK) { // Paper - BlockHitResult positionBlock = (BlockHitResult) position; - hitBlock = CraftBlock.at(potion.level(), positionBlock.getBlockPos()); - hitFace = CraftBlock.notchToBlockFace(positionBlock.getDirection()); - } - - org.bukkit.entity.Entity hitEntity = null; -- if (position.getType() == HitResult.Type.ENTITY) { -+ if (position != null && position.getType() == HitResult.Type.ENTITY) { // Paper - hitEntity = ((EntityHitResult) position).getEntity().getBukkitEntity(); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 60062ea5b18b95a14c459f2f3a0743c1e1ac0f12..502be683e8b04a9966043c9bee9d9fe793b12ef5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -341,12 +341,23 @@ public final class CraftItemStack extends ItemStack { - public ItemMeta getItemMeta() { - return CraftItemStack.getItemMeta(this.handle); - } -+ // Paper start -+ public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { -+ final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); -+ ((CraftMetaItem) itemMeta).applyToItem(tag); -+ itemStack.applyComponents(tag.build()); -+ } - - public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item) { -+ return getItemMeta(item, null); -+ } -+ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType) { -+ // Paper end - if (!CraftItemStack.hasItemMeta(item)) { - return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item)); - } - -+ if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item); } // Paper - return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java -index 642f5bf75661eb485558bc227f668e84416f3b5f..76fd4d27730d9139caa67099a6757ea33d681be9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java -+++ b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java -@@ -56,7 +56,15 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { - - @Override - public T launchProjectile(Class projectile, Vector velocity) { -+ // Paper start - launchProjectile consumer -+ return this.launchProjectile(projectile, velocity, null); -+ } -+ -+ @Override -+ public T launchProjectile(Class projectile, Vector velocity, java.util.function.Consumer function) { -+ // Paper end - launchProjectile consumer - Preconditions.checkArgument(this.getBlock().getType() == Material.DISPENSER, "Block is no longer dispenser"); -+ - // Copied from BlockDispenser.dispense() - BlockSource sourceblock = new BlockSource((ServerLevel) this.dispenserBlock.getLevel(), this.dispenserBlock.getBlockPos(), this.dispenserBlock.getBlockState(), this.dispenserBlock); - // Copied from DispenseBehaviorProjectile -@@ -68,7 +76,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { - item = Items.SNOWBALL; - } else if (Egg.class.isAssignableFrom(projectile)) { - item = Items.EGG; -- } else if (EnderPearl.class.isAssignableFrom(projectile)) { -+ } else if (false && EnderPearl.class.isAssignableFrom(projectile)) { // Paper - more projectile API - disallow enderpearl, it is not a projectile item - item = Items.ENDER_PEARL; - } else if (ThrownExpBottle.class.isAssignableFrom(projectile)) { - item = Items.EXPERIENCE_BOTTLE; -@@ -83,20 +91,20 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { - item = Items.TIPPED_ARROW; - } else if (SpectralArrow.class.isAssignableFrom(projectile)) { - item = Items.SPECTRAL_ARROW; -- } else { -+ } else if (org.bukkit.entity.Arrow.class.isAssignableFrom(projectile)) { // Paper - more projectile API - disallow trident - item = Items.ARROW; - } - } else if (Fireball.class.isAssignableFrom(projectile)) { -- if (AbstractWindCharge.class.isAssignableFrom(projectile)) { -+ if (org.bukkit.entity.WindCharge.class.isAssignableFrom(projectile)) { // Paper - more projectile API - only allow wind charge not breeze wind charge - item = Items.WIND_CHARGE; -- } else { -+ } else if (org.bukkit.entity.SmallFireball.class.isAssignableFrom(projectile)) { // Paper - more projectile API - only allow firing fire charges. - item = Items.FIRE_CHARGE; - } - } else if (Firework.class.isAssignableFrom(projectile)) { - item = Items.FIREWORK_ROCKET; - } - -- Preconditions.checkArgument(item instanceof ProjectileItem, "Projectile not supported"); -+ Preconditions.checkArgument(item instanceof ProjectileItem, "Projectile '%s' not supported", projectile.getSimpleName()); // Paper - more projectile API - include simple name in exception - - ItemStack itemstack = new ItemStack(item); - ProjectileItem projectileItem = (ProjectileItem) item; -@@ -105,7 +113,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { - Position iposition = dispenseConfig.positionFunction().getDispensePosition(sourceblock, enumdirection); - net.minecraft.world.entity.projectile.Projectile launch = projectileItem.asProjectile(world, iposition, itemstack, enumdirection); - -- if (Fireball.class.isAssignableFrom(projectile)) { -+ if (false && Fireball.class.isAssignableFrom(projectile)) { // Paper - more project API - dispensers cannot launch anything but fire charges. - AbstractHurtingProjectile customFireball = null; - if (WitherSkull.class.isAssignableFrom(projectile)) { - launch = customFireball = EntityType.WITHER_SKULL.create(world, EntitySpawnReason.TRIGGERED); -@@ -130,7 +138,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { - } - } - -- if (launch instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) { -+ if (false && launch instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) { // Paper - more projectile API - this is set by the respective ArrowItem when constructing the projectile - arrow.pickup = net.minecraft.world.entity.projectile.AbstractArrow.Pickup.ALLOWED; - } - launch.projectileSource = this; -@@ -139,6 +147,11 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { - if (velocity != null) { - ((T) launch.getBukkitEntity()).setVelocity(velocity); - } -+ // Paper start -+ if (function != null) { -+ function.accept((T) launch.getBukkitEntity()); -+ } -+ // Paper end - - world.addFreshEntity(launch); - return (T) launch.getBukkitEntity(); diff --git a/patches/server/0671-Don-t-allow-vehicle-movement-from-players-while-tele.patch b/patches/server/0671-Don-t-allow-vehicle-movement-from-players-while-tele.patch new file mode 100644 index 0000000000..cb7a4055d9 --- /dev/null +++ b/patches/server/0671-Don-t-allow-vehicle-movement-from-players-while-tele.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 14 Mar 2022 12:35:37 -0700 +Subject: [PATCH] Don't allow vehicle movement from players while teleporting + +Bring the vehicle move packet behavior in line with the +regular player move packet. + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 7f1e0c6801a1d8b0857fba9826fc56e30bd41497..9656e15aa15735e9bd6ac4e2ad7aa8aa66140b9a 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -489,6 +489,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_vehicle_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_VEHICLE_MOVEMENT); // Paper - kick event cause + } else if (!this.updateAwaitingTeleport()) { + Entity entity = this.player.getRootVehicle(); ++ // Paper start - Don't allow vehicle movement from players while teleporting ++ if (this.awaitingPositionFromClient != null || this.player.isImmobile() || entity.isRemoved()) { ++ return; ++ } ++ // Paper end - Don't allow vehicle movement from players while teleporting + + if (entity != this.player && entity.getControllingPassenger() == this.player && entity == this.lastVehicle) { + ServerLevel worldserver = this.player.serverLevel(); diff --git a/patches/server/0671-Fix-swamp-hut-cat-generation-deadlock.patch b/patches/server/0671-Fix-swamp-hut-cat-generation-deadlock.patch deleted file mode 100644 index 24bfbc0dc7..0000000000 --- a/patches/server/0671-Fix-swamp-hut-cat-generation-deadlock.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 12 Mar 2022 06:31:13 -0800 -Subject: [PATCH] Fix swamp hut cat generation deadlock - -The worldgen thread will attempt to get structure references -via the world's getChunkAt method, which is fine if the gen is -not cancelled - but if the chunk was unloaded, the call will block -indefinitely. Instead of using the world state, we use the already -supplied ServerLevelAccessor which will always have the chunk available. - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index f3a991aa878f3b29fdc525ecdde6766efb5e129c..5a86530c65d7d83e4608600a04ffd931bf59dc4a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -366,7 +366,7 @@ public class Cat extends TamableAnimal implements VariantHolder startsForStructure(ChunkPos pos, Predicate predicate) { -- Map map = this.level.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); -+ // Paper start - Fix swamp hut cat generation deadlock -+ return this.startsForStructure(pos, predicate, null); -+ } -+ public List startsForStructure(ChunkPos pos, Predicate predicate, @Nullable ServerLevelAccessor levelAccessor) { -+ Map map = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); -+ // Paper end - Fix swamp hut cat generation deadlock - Builder builder = ImmutableList.builder(); - - for (Entry entry : map.entrySet()) { -@@ -116,10 +121,20 @@ public class StructureManager { - } - - public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate) { -+ // Paper start - Fix swamp hut cat generation deadlock -+ return this.getStructureWithPieceAt(pos, predicate, null); -+ } -+ -+ public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey tag, @Nullable ServerLevelAccessor levelAccessor) { -+ return this.getStructureWithPieceAt(pos, structure -> structure.is(tag), levelAccessor); -+ } -+ -+ public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate, @Nullable ServerLevelAccessor levelAccessor) { -+ // Paper end - Fix swamp hut cat generation deadlock - Registry registry = this.registryAccess().lookupOrThrow(Registries.STRUCTURE); - - for (StructureStart structureStart : this.startsForStructure( -- new ChunkPos(pos), structure -> registry.get(registry.getId(structure)).map(predicate::test).orElse(false) -+ new ChunkPos(pos), structure -> registry.get(registry.getId(structure)).map(predicate::test).orElse(false), levelAccessor // Paper - Fix swamp hut cat generation deadlock - )) { - if (this.structureHasPieceAt(pos, structureStart)) { - return structureStart; diff --git a/patches/server/0672-Don-t-allow-vehicle-movement-from-players-while-tele.patch b/patches/server/0672-Don-t-allow-vehicle-movement-from-players-while-tele.patch deleted file mode 100644 index c8f2f8a3b8..0000000000 --- a/patches/server/0672-Don-t-allow-vehicle-movement-from-players-while-tele.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 14 Mar 2022 12:35:37 -0700 -Subject: [PATCH] Don't allow vehicle movement from players while teleporting - -Bring the vehicle move packet behavior in line with the -regular player move packet. - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0790d904a408652c593dc8d87b1b2087169e7490..65e0ad4cae47a1912ad12ea1e6eaa3672d4f12e8 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -489,6 +489,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_vehicle_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_VEHICLE_MOVEMENT); // Paper - kick event cause - } else if (!this.updateAwaitingTeleport()) { - Entity entity = this.player.getRootVehicle(); -+ // Paper start - Don't allow vehicle movement from players while teleporting -+ if (this.awaitingPositionFromClient != null || this.player.isImmobile() || entity.isRemoved()) { -+ return; -+ } -+ // Paper end - Don't allow vehicle movement from players while teleporting - - if (entity != this.player && entity.getControllingPassenger() == this.player && entity == this.lastVehicle) { - ServerLevel worldserver = this.player.serverLevel(); diff --git a/patches/server/0672-Implement-getComputedBiome-API.patch b/patches/server/0672-Implement-getComputedBiome-API.patch new file mode 100644 index 0000000000..dab55a6218 --- /dev/null +++ b/patches/server/0672-Implement-getComputedBiome-API.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Mon, 14 Mar 2022 22:46:05 -0700 +Subject: [PATCH] Implement getComputedBiome API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +index ca35e93239eea09b3d0dc6ef18f58743e633996b..a7748f4b7c5a1630937c702b3fd5fded93793d64 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +@@ -77,6 +77,13 @@ public abstract class CraftRegionAccessor implements RegionAccessor { + return CraftBiome.minecraftHolderToBukkit(this.getHandle().getNoiseBiome(x >> 2, y >> 2, z >> 2)); + } + ++ // Paper start ++ @Override ++ public Biome getComputedBiome(int x, int y, int z) { ++ return CraftBiome.minecraftHolderToBukkit(this.getHandle().getBiome(new BlockPos(x, y, z))); ++ } ++ // Paper end ++ + @Override + public void setBiome(Location location, Biome biome) { + this.setBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ(), biome); +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index d5b495b5a3ca7f4411d1a700f7149042a16509f1..68fcec085334383808b2117a49220f4d8239220b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -340,6 +340,13 @@ public class CraftBlock implements Block { + return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ()); + } + ++ // Paper start ++ @Override ++ public Biome getComputedBiome() { ++ return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ()); ++ } ++ // Paper end ++ + @Override + public void setBiome(Biome bio) { + this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio); +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +index 2c7b64bd7071cb803a042152d497982d753e0b5d..a23269e3bdb83f85a1d08d5f7b54742025223ada 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +@@ -166,6 +166,14 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe + return super.getBiome(x, y, z); + } + ++ // Paper start ++ @Override ++ public Biome getComputedBiome(int x, int y, int z) { ++ Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); ++ return super.getComputedBiome(x, y, z); ++ } ++ // Paper end ++ + @Override + public void setBiome(int x, int y, int z, Holder biomeBase) { + Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); diff --git a/patches/server/0673-Implement-getComputedBiome-API.patch b/patches/server/0673-Implement-getComputedBiome-API.patch deleted file mode 100644 index dab55a6218..0000000000 --- a/patches/server/0673-Implement-getComputedBiome-API.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Mon, 14 Mar 2022 22:46:05 -0700 -Subject: [PATCH] Implement getComputedBiome API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -index ca35e93239eea09b3d0dc6ef18f58743e633996b..a7748f4b7c5a1630937c702b3fd5fded93793d64 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -@@ -77,6 +77,13 @@ public abstract class CraftRegionAccessor implements RegionAccessor { - return CraftBiome.minecraftHolderToBukkit(this.getHandle().getNoiseBiome(x >> 2, y >> 2, z >> 2)); - } - -+ // Paper start -+ @Override -+ public Biome getComputedBiome(int x, int y, int z) { -+ return CraftBiome.minecraftHolderToBukkit(this.getHandle().getBiome(new BlockPos(x, y, z))); -+ } -+ // Paper end -+ - @Override - public void setBiome(Location location, Biome biome) { - this.setBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ(), biome); -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index d5b495b5a3ca7f4411d1a700f7149042a16509f1..68fcec085334383808b2117a49220f4d8239220b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -340,6 +340,13 @@ public class CraftBlock implements Block { - return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ()); - } - -+ // Paper start -+ @Override -+ public Biome getComputedBiome() { -+ return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ()); -+ } -+ // Paper end -+ - @Override - public void setBiome(Biome bio) { - this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio); -diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -index 2c7b64bd7071cb803a042152d497982d753e0b5d..a23269e3bdb83f85a1d08d5f7b54742025223ada 100644 ---- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -@@ -166,6 +166,14 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe - return super.getBiome(x, y, z); - } - -+ // Paper start -+ @Override -+ public Biome getComputedBiome(int x, int y, int z) { -+ Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); -+ return super.getComputedBiome(x, y, z); -+ } -+ // Paper end -+ - @Override - public void setBiome(int x, int y, int z, Holder biomeBase) { - Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); diff --git a/patches/server/0673-Make-some-itemstacks-nonnull.patch b/patches/server/0673-Make-some-itemstacks-nonnull.patch new file mode 100644 index 0000000000..20944d9088 --- /dev/null +++ b/patches/server/0673-Make-some-itemstacks-nonnull.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 15 Mar 2022 01:38:15 -0700 +Subject: [PATCH] Make some itemstacks nonnull + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java +index 107fa1d4bd977d17dc062da280dda46eb3c5f81c..e62baea16df017f1e394e3c706157e158066eb93 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java +@@ -155,13 +155,13 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i + case OFF_HAND: + return this.getItemInOffHand(); + case FEET: +- return this.getBoots(); ++ return java.util.Objects.requireNonNullElseGet(this.getBoots(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull + case LEGS: +- return this.getLeggings(); ++ return java.util.Objects.requireNonNullElseGet(this.getLeggings(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull + case CHEST: +- return this.getChestplate(); ++ return java.util.Objects.requireNonNullElseGet(this.getChestplate(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull + case HEAD: +- return this.getHelmet(); ++ return java.util.Objects.requireNonNullElseGet(this.getHelmet(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull + default: + throw new IllegalArgumentException("Could not get slot " + slot + " - not a valid slot for PlayerInventory"); + } diff --git a/patches/server/0674-Implement-enchantWithLevels-API.patch b/patches/server/0674-Implement-enchantWithLevels-API.patch new file mode 100644 index 0000000000..45f1f704ca --- /dev/null +++ b/patches/server/0674-Implement-enchantWithLevels-API.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 16 Mar 2022 20:35:21 -0700 +Subject: [PATCH] Implement enchantWithLevels API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +index ad86ee4372e55c82968fd4fc6a65debab0092028..d9eec6cff3c7c6515f4d61bf1063e7d609d4bcb3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +@@ -305,4 +305,47 @@ public final class CraftItemFactory implements ItemFactory { + return eggItem == null ? null : new net.minecraft.world.item.ItemStack(eggItem).asBukkitMirror(); + } + // Paper end - old getSpawnEgg API ++ // Paper start - enchantWithLevels API ++ @Override ++ public ItemStack enchantWithLevels(ItemStack itemStack, int levels, boolean allowTreasure, java.util.Random random) { ++ return enchantWithLevels( ++ itemStack, ++ levels, ++ allowTreasure ++ ? Optional.empty() ++ // While IN_ENCHANTING_TABLE is not logically the same as all but TREASURE, the tag is defined as ++ // NON_TREASURE, which does contain all enchantments not in the treasure tag. ++ // Additionally, the allowTreasure boolean is more intended to configure this method to behave like ++ // an enchanting table. ++ : net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.ENCHANTMENT).get(EnchantmentTags.IN_ENCHANTING_TABLE), ++ random ++ ); ++ } ++ ++ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") ++ private ItemStack enchantWithLevels( ++ ItemStack itemStack, ++ int levels, ++ Optional> possibleEnchantments, ++ java.util.Random random ++ ) { ++ Preconditions.checkArgument(itemStack != null, "Argument 'itemStack' must not be null"); ++ Preconditions.checkArgument(!itemStack.isEmpty(), "Argument 'itemStack' cannot be empty"); ++ Preconditions.checkArgument(levels > 0 && levels <= 30, "Argument 'levels' must be in range [1, 30] (attempted " + levels + ")"); ++ Preconditions.checkArgument(random != null, "Argument 'random' must not be null"); ++ final net.minecraft.world.item.ItemStack internalStack = CraftItemStack.asNMSCopy(itemStack); ++ if (internalStack.isEnchanted()) { ++ internalStack.set(net.minecraft.core.component.DataComponents.ENCHANTMENTS, net.minecraft.world.item.enchantment.ItemEnchantments.EMPTY); ++ } ++ final net.minecraft.core.RegistryAccess registryAccess = net.minecraft.server.MinecraftServer.getServer().registryAccess(); ++ final net.minecraft.world.item.ItemStack enchanted = net.minecraft.world.item.enchantment.EnchantmentHelper.enchantItem( ++ new org.bukkit.craftbukkit.util.RandomSourceWrapper(random), ++ internalStack, ++ levels, ++ registryAccess, ++ possibleEnchantments ++ ); ++ return CraftItemStack.asCraftMirror(enchanted); ++ } ++ // Paper end - enchantWithLevels API + } diff --git a/patches/server/0674-Make-some-itemstacks-nonnull.patch b/patches/server/0674-Make-some-itemstacks-nonnull.patch deleted file mode 100644 index 20944d9088..0000000000 --- a/patches/server/0674-Make-some-itemstacks-nonnull.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 15 Mar 2022 01:38:15 -0700 -Subject: [PATCH] Make some itemstacks nonnull - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java -index 107fa1d4bd977d17dc062da280dda46eb3c5f81c..e62baea16df017f1e394e3c706157e158066eb93 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java -@@ -155,13 +155,13 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i - case OFF_HAND: - return this.getItemInOffHand(); - case FEET: -- return this.getBoots(); -+ return java.util.Objects.requireNonNullElseGet(this.getBoots(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull - case LEGS: -- return this.getLeggings(); -+ return java.util.Objects.requireNonNullElseGet(this.getLeggings(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull - case CHEST: -- return this.getChestplate(); -+ return java.util.Objects.requireNonNullElseGet(this.getChestplate(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull - case HEAD: -- return this.getHelmet(); -+ return java.util.Objects.requireNonNullElseGet(this.getHelmet(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull - default: - throw new IllegalArgumentException("Could not get slot " + slot + " - not a valid slot for PlayerInventory"); - } diff --git a/patches/server/0675-Fix-saving-in-unloadWorld.patch b/patches/server/0675-Fix-saving-in-unloadWorld.patch new file mode 100644 index 0000000000..a715afca0e --- /dev/null +++ b/patches/server/0675-Fix-saving-in-unloadWorld.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Philip Kelley +Date: Wed, 16 Mar 2022 12:05:59 +0000 +Subject: [PATCH] Fix saving in unloadWorld + +Change savingDisabled to false to ensure ServerLevel's saving logic gets called when unloadWorld is called with save = true + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 3b48a8107bf0b4326b86ee08bb54341825be81c1..a504a6458423a997e703e95356dd2058d6c164e2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1385,7 +1385,7 @@ public final class CraftServer implements Server { + + try { + if (save) { +- handle.save(null, true, true); ++ handle.save(null, true, false); // Paper - Fix saving in unloadWorld + } + + handle.getChunkSource().close(save); diff --git a/patches/server/0675-Implement-enchantWithLevels-API.patch b/patches/server/0675-Implement-enchantWithLevels-API.patch deleted file mode 100644 index 45f1f704ca..0000000000 --- a/patches/server/0675-Implement-enchantWithLevels-API.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 16 Mar 2022 20:35:21 -0700 -Subject: [PATCH] Implement enchantWithLevels API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -index ad86ee4372e55c82968fd4fc6a65debab0092028..d9eec6cff3c7c6515f4d61bf1063e7d609d4bcb3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -@@ -305,4 +305,47 @@ public final class CraftItemFactory implements ItemFactory { - return eggItem == null ? null : new net.minecraft.world.item.ItemStack(eggItem).asBukkitMirror(); - } - // Paper end - old getSpawnEgg API -+ // Paper start - enchantWithLevels API -+ @Override -+ public ItemStack enchantWithLevels(ItemStack itemStack, int levels, boolean allowTreasure, java.util.Random random) { -+ return enchantWithLevels( -+ itemStack, -+ levels, -+ allowTreasure -+ ? Optional.empty() -+ // While IN_ENCHANTING_TABLE is not logically the same as all but TREASURE, the tag is defined as -+ // NON_TREASURE, which does contain all enchantments not in the treasure tag. -+ // Additionally, the allowTreasure boolean is more intended to configure this method to behave like -+ // an enchanting table. -+ : net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.ENCHANTMENT).get(EnchantmentTags.IN_ENCHANTING_TABLE), -+ random -+ ); -+ } -+ -+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") -+ private ItemStack enchantWithLevels( -+ ItemStack itemStack, -+ int levels, -+ Optional> possibleEnchantments, -+ java.util.Random random -+ ) { -+ Preconditions.checkArgument(itemStack != null, "Argument 'itemStack' must not be null"); -+ Preconditions.checkArgument(!itemStack.isEmpty(), "Argument 'itemStack' cannot be empty"); -+ Preconditions.checkArgument(levels > 0 && levels <= 30, "Argument 'levels' must be in range [1, 30] (attempted " + levels + ")"); -+ Preconditions.checkArgument(random != null, "Argument 'random' must not be null"); -+ final net.minecraft.world.item.ItemStack internalStack = CraftItemStack.asNMSCopy(itemStack); -+ if (internalStack.isEnchanted()) { -+ internalStack.set(net.minecraft.core.component.DataComponents.ENCHANTMENTS, net.minecraft.world.item.enchantment.ItemEnchantments.EMPTY); -+ } -+ final net.minecraft.core.RegistryAccess registryAccess = net.minecraft.server.MinecraftServer.getServer().registryAccess(); -+ final net.minecraft.world.item.ItemStack enchanted = net.minecraft.world.item.enchantment.EnchantmentHelper.enchantItem( -+ new org.bukkit.craftbukkit.util.RandomSourceWrapper(random), -+ internalStack, -+ levels, -+ registryAccess, -+ possibleEnchantments -+ ); -+ return CraftItemStack.asCraftMirror(enchanted); -+ } -+ // Paper end - enchantWithLevels API - } diff --git a/patches/server/0676-Buffer-OOB-setBlock-calls.patch b/patches/server/0676-Buffer-OOB-setBlock-calls.patch new file mode 100644 index 0000000000..1b7ba291c4 --- /dev/null +++ b/patches/server/0676-Buffer-OOB-setBlock-calls.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sat, 19 Mar 2022 12:12:22 +0000 +Subject: [PATCH] Buffer OOB setBlock calls + +lets debug mode throw a trace in order to potentially see where +such calls are cascading from easier, but, generally, if you see one setBlock +call, you're gonna see more, and this just potentially causes a flood of logs +which can cause issues for slower terminals, etc. + +We can limit the flood by just allowing one for a single gen region, +we'll also only gen a trace for the first one, I see no real pressing need +to generate more, given that that would *massively* negate this patch otherwise + +diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java +index f1725ef766c35aa623ace58fe8bf31fc9b2bb6b3..5bf438bb58833c1df3620e82d3d2b90207366372 100644 +--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java ++++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java +@@ -284,6 +284,7 @@ public class WorldGenRegion implements WorldGenLevel { + } + } + ++ private boolean hasSetFarWarned = false; // Paper - Buffer OOB setBlock calls + @Override + public boolean ensureCanWrite(BlockPos pos) { + int i = SectionPos.blockToSectionCoord(pos.getX()); +@@ -303,7 +304,15 @@ public class WorldGenRegion implements WorldGenLevel { + + return true; + } else { ++ // Paper start - Buffer OOB setBlock calls ++ if (!hasSetFarWarned) { + Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStep.targetStatus()) + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get())); ++ hasSetFarWarned = true; ++ if (this.getServer() != null && this.getServer().isDebugging()) { ++ io.papermc.paper.util.TraceUtil.dumpTraceForThread("far setBlock call"); ++ } ++ } ++ // Paper end - Buffer OOB setBlock calls + return false; + } + } diff --git a/patches/server/0676-Fix-saving-in-unloadWorld.patch b/patches/server/0676-Fix-saving-in-unloadWorld.patch deleted file mode 100644 index f2d01904b1..0000000000 --- a/patches/server/0676-Fix-saving-in-unloadWorld.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Philip Kelley -Date: Wed, 16 Mar 2022 12:05:59 +0000 -Subject: [PATCH] Fix saving in unloadWorld - -Change savingDisabled to false to ensure ServerLevel's saving logic gets called when unloadWorld is called with save = true - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index b3e5fc3a417be2af8ed6591f67f8d56c4ca86d74..2860aa8f75ec5901023f88047cb4cb96298a99e0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1386,7 +1386,7 @@ public final class CraftServer implements Server { - - try { - if (save) { -- handle.save(null, true, true); -+ handle.save(null, true, false); // Paper - Fix saving in unloadWorld - } - - handle.getChunkSource().close(save); diff --git a/patches/server/0677-Add-TameableDeathMessageEvent.patch b/patches/server/0677-Add-TameableDeathMessageEvent.patch new file mode 100644 index 0000000000..641b0b0e37 --- /dev/null +++ b/patches/server/0677-Add-TameableDeathMessageEvent.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Mon, 21 Jun 2021 21:24:45 -0400 +Subject: [PATCH] Add TameableDeathMessageEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +index cd565d1a8dab8d45196e4d29cab3d93a3ca619eb..749ae54ee42229cb32ec5280bc59a88f74fde197 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -250,7 +250,12 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + if (entityliving instanceof ServerPlayer) { + ServerPlayer entityplayer = (ServerPlayer) entityliving; + +- entityplayer.sendSystemMessage(this.getCombatTracker().getDeathMessage()); ++ // Paper start - Add TameableDeathMessageEvent ++ io.papermc.paper.event.entity.TameableDeathMessageEvent event = new io.papermc.paper.event.entity.TameableDeathMessageEvent((org.bukkit.entity.Tameable) getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getCombatTracker().getDeathMessage())); ++ if (event.callEvent()) { ++ entityplayer.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.deathMessage())); ++ } ++ // Paper end - Add TameableDeathMessageEvent + } + } + } diff --git a/patches/server/0677-Buffer-OOB-setBlock-calls.patch b/patches/server/0677-Buffer-OOB-setBlock-calls.patch deleted file mode 100644 index 1b7ba291c4..0000000000 --- a/patches/server/0677-Buffer-OOB-setBlock-calls.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sat, 19 Mar 2022 12:12:22 +0000 -Subject: [PATCH] Buffer OOB setBlock calls - -lets debug mode throw a trace in order to potentially see where -such calls are cascading from easier, but, generally, if you see one setBlock -call, you're gonna see more, and this just potentially causes a flood of logs -which can cause issues for slower terminals, etc. - -We can limit the flood by just allowing one for a single gen region, -we'll also only gen a trace for the first one, I see no real pressing need -to generate more, given that that would *massively* negate this patch otherwise - -diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index f1725ef766c35aa623ace58fe8bf31fc9b2bb6b3..5bf438bb58833c1df3620e82d3d2b90207366372 100644 ---- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java -+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -284,6 +284,7 @@ public class WorldGenRegion implements WorldGenLevel { - } - } - -+ private boolean hasSetFarWarned = false; // Paper - Buffer OOB setBlock calls - @Override - public boolean ensureCanWrite(BlockPos pos) { - int i = SectionPos.blockToSectionCoord(pos.getX()); -@@ -303,7 +304,15 @@ public class WorldGenRegion implements WorldGenLevel { - - return true; - } else { -+ // Paper start - Buffer OOB setBlock calls -+ if (!hasSetFarWarned) { - Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStep.targetStatus()) + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get())); -+ hasSetFarWarned = true; -+ if (this.getServer() != null && this.getServer().isDebugging()) { -+ io.papermc.paper.util.TraceUtil.dumpTraceForThread("far setBlock call"); -+ } -+ } -+ // Paper end - Buffer OOB setBlock calls - return false; - } - } diff --git a/patches/server/0678-Add-TameableDeathMessageEvent.patch b/patches/server/0678-Add-TameableDeathMessageEvent.patch deleted file mode 100644 index 641b0b0e37..0000000000 --- a/patches/server/0678-Add-TameableDeathMessageEvent.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Mon, 21 Jun 2021 21:24:45 -0400 -Subject: [PATCH] Add TameableDeathMessageEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -index cd565d1a8dab8d45196e4d29cab3d93a3ca619eb..749ae54ee42229cb32ec5280bc59a88f74fde197 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -250,7 +250,12 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { - if (entityliving instanceof ServerPlayer) { - ServerPlayer entityplayer = (ServerPlayer) entityliving; - -- entityplayer.sendSystemMessage(this.getCombatTracker().getDeathMessage()); -+ // Paper start - Add TameableDeathMessageEvent -+ io.papermc.paper.event.entity.TameableDeathMessageEvent event = new io.papermc.paper.event.entity.TameableDeathMessageEvent((org.bukkit.entity.Tameable) getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getCombatTracker().getDeathMessage())); -+ if (event.callEvent()) { -+ entityplayer.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.deathMessage())); -+ } -+ // Paper end - Add TameableDeathMessageEvent - } - } - } diff --git a/patches/server/0678-Fix-new-block-data-for-EntityChangeBlockEvent.patch b/patches/server/0678-Fix-new-block-data-for-EntityChangeBlockEvent.patch new file mode 100644 index 0000000000..fce021dda2 --- /dev/null +++ b/patches/server/0678-Fix-new-block-data-for-EntityChangeBlockEvent.patch @@ -0,0 +1,215 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Mon, 21 Mar 2022 20:00:53 +0200 +Subject: [PATCH] Fix new block data for EntityChangeBlockEvent + +Also standardizes how to handle EntityChangeBlockEvent before a removeBlock or destroyBlock +call. Always use 'state.getFluidState().createLegacyBlock()' to get the new state instead of +just using the 'air' state. + +Also fixes the new block data for EntityBreakDoorEvent (a sub-event from +EntityChangeBlockEvent) + +Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +index 6a7052cd6ec88ed4aaea2fef0ebc750060d1dec0..2ade08d1466660ee1787fa97908002ef56389712 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +@@ -108,7 +108,7 @@ public class HarvestFarmland extends Behavior { + Block block1 = world.getBlockState(this.aboveFarmlandPos.below()).getBlock(); + + if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata)) { +- if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, Blocks.AIR.defaultBlockState())) { // CraftBukkit ++ if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state + world.destroyBlock(this.aboveFarmlandPos, true, entity); + } // CraftBukkit + } +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java +index e2aa6d46375cbc4f4b694888c4f9750eb26e4940..6827426e6e9706909265f84bf97b5fa7105a7fea 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java +@@ -73,7 +73,7 @@ public class BreakDoorGoal extends DoorInteractGoal { + + if (this.breakTime == this.getDoorBreakTime() && this.isValidDifficulty(this.mob.level().getDifficulty())) { + // CraftBukkit start +- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.mob, this.doorPos).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.mob, this.doorPos, this.mob.level().getFluidState(this.doorPos).createLegacyBlock()).isCancelled()) { // Paper - fix wrong block state + this.start(); + return; + } +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java +index dc3602002e60d64cbbe9504c22282a9e65da2c9d..9e6f946e6d2878aa3fa8abe0f6fa4770d18676d3 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java +@@ -67,8 +67,9 @@ public class EatBlockGoal extends Goal { + if (this.eatAnimationTick == this.adjustedTickDelay(4)) { + BlockPos blockposition = this.mob.blockPosition(); + +- if (EatBlockGoal.IS_TALL_GRASS.test(this.level.getBlockState(blockposition))) { +- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, Blocks.AIR.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit ++ final BlockState blockState = this.level.getBlockState(blockposition); // Paper - fix wrong block state ++ if (EatBlockGoal.IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state ++ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state + this.level.destroyBlock(blockposition, false); + } + +@@ -77,7 +78,7 @@ public class EatBlockGoal extends Goal { + BlockPos blockposition1 = blockposition.below(); + + if (this.level.getBlockState(blockposition1).is(Blocks.GRASS_BLOCK)) { +- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.AIR.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit ++ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state + this.level.levelEvent(2001, blockposition1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState())); + this.level.setBlock(blockposition1, Blocks.DIRT.defaultBlockState(), 2); + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java +index a2bbb79f2999e719b8c80d33e530391ec3d1d2d2..8cc6022507c97af62fb2b4455198bc35744137c9 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java +@@ -580,7 +580,7 @@ public class Rabbit extends Animal implements VariantHolder { + + if (i == 0) { + // CraftBukkit start +- if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, Blocks.AIR.defaultBlockState())) { ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + return; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +index b145023308e6a2823d83db97ff2d79c38b709ef9..e6b18d7f8922cb42acb9e40bef2f71a56aea8646 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -375,7 +375,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { + + if (WitherBoss.canDestroy(iblockdata)) { + // CraftBukkit start +- if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, Blocks.AIR.defaultBlockState())) { ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + continue; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +index 0e8349aa6cb23860a4dd884e730ac8f22d422205..48dcd2bc12ce1d08cc5195bff5460dc0dd9902d3 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +@@ -552,7 +552,7 @@ public class EnderMan extends Monster implements NeutralMob { + boolean flag = movingobjectpositionblock.getBlockPos().equals(blockposition); + + if (iblockdata.is(BlockTags.ENDERMAN_HOLDABLE) && flag) { +- if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, Blocks.AIR.defaultBlockState())) { // CraftBukkit - Place event ++ if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit - Place event // Paper - fix wrong block state + world.removeBlock(blockposition, false); + world.gameEvent((Holder) GameEvent.BLOCK_DESTROY, blockposition, GameEvent.Context.of(this.enderman, iblockdata)); + this.enderman.setCarriedBlock(iblockdata.getBlock().defaultBlockState()); +diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java +index c661ae4e5c07494c7de852cc8d01f0f9839c1590..c96fbfe448b3e7b722a8db0e1688276776abd94e 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java +@@ -165,7 +165,7 @@ public class Ravager extends Raider { + + if (block instanceof LeavesBlock) { + // CraftBukkit start +- if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + continue; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java +index 52d8ea3e40cdb01eab428f5d3d945c0c9f6088ce..ff65cb8ea5233f2dd159f42ad53bc9d300cd604f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java +@@ -165,7 +165,8 @@ public class Silverfish extends Monster { + + if (block instanceof InfestedBlock) { + // CraftBukkit start +- if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { ++ BlockState afterState = getServerLevel(world).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? iblockdata.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1)); // Paper - fix wrong block state ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, afterState)) { // Paper - fix wrong block state + continue; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +index a486466040a646b8a5a5ff2430cdd25b95b7e20f..e78eef3b6fbcd657f9dd180df4cb2eeb55d0814f 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +@@ -294,7 +294,7 @@ public class ThrownPotion extends ThrowableItemProjectile { + + if (iblockdata.is(BlockTags.FIRE)) { + // CraftBukkit start +- if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, Blocks.AIR.defaultBlockState())) { ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + this.level().destroyBlock(pos, false, this); + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java b/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java +index fae574f8617bada96469a2eb1349eaa061f0450f..6d0d13e70a82c4db7848e1007f5b6d670dd5acad 100644 +--- a/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java +@@ -286,7 +286,7 @@ public class ChorusFlowerBlock extends Block { + if (world instanceof ServerLevel worldserver) { + if (projectile.mayInteract(worldserver, blockposition) && projectile.mayBreak(worldserver)) { + // CraftBukkit +- if (!CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState())) { ++ if (!CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + return; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java +index 48503f5ba8bccb42ae3b5324a5f65f6c23a8e479..bd38a0a73d543a85bb5c6d50219f5438ce194df3 100644 +--- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java +@@ -137,7 +137,7 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate + + if (projectile.mayInteract(worldserver, blockposition) && projectile.mayBreak(worldserver) && projectile instanceof ThrownTrident && projectile.getDeltaMovement().length() > 0.6D) { + // CraftBukkit start +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState())) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + return; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/level/block/TntBlock.java b/src/main/java/net/minecraft/world/level/block/TntBlock.java +index d256b0f3998028709334dd6c394d184f2c36efce..2cbe2053dd5d0bcdcd89de69762c77b400b8697a 100644 +--- a/src/main/java/net/minecraft/world/level/block/TntBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/TntBlock.java +@@ -158,7 +158,7 @@ public class TntBlock extends Block { + + if (projectile.isOnFire() && projectile.mayInteract(worldserver, blockposition)) { + // CraftBukkit start +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState()) || !CraftEventFactory.callTNTPrimeEvent(world, blockposition, PrimeCause.PROJECTILE, projectile, null)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock()) || !CraftEventFactory.callTNTPrimeEvent(world, blockposition, PrimeCause.PROJECTILE, projectile, null)) { // Paper - fix wrong block state + return; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java +index 674d710ff88db5eced9e017284d1b7ec7a4fe7cd..72320c6099a4b26235bab68570e7b7efad84740f 100644 +--- a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java +@@ -37,7 +37,7 @@ public class WaterlilyBlock extends BushBlock { + super.entityInside(state, world, pos, entity); + if (world instanceof ServerLevel && entity instanceof AbstractBoat) { + // CraftBukkit start +- if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState())) { ++ if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + return; + } + // CraftBukkit end +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index e0418c0c36aa99ea43dbf39fa176ddf8855e0568..f54a4c263eeb4df40c72c20c3c480ce74718a718 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1378,11 +1378,11 @@ public class CraftEventFactory { + return event; + } + +- public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos) { ++ public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos, net.minecraft.world.level.block.state.BlockState newState) { // Paper + org.bukkit.entity.Entity entity1 = entity.getBukkitEntity(); + Block block = CraftBlock.at(entity.level(), pos); + +- EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block); ++ EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block, newState.createCraftBlockData()); // Paper + entity1.getServer().getPluginManager().callEvent(event); + + return event; diff --git a/patches/server/0679-Fix-new-block-data-for-EntityChangeBlockEvent.patch b/patches/server/0679-Fix-new-block-data-for-EntityChangeBlockEvent.patch deleted file mode 100644 index fce021dda2..0000000000 --- a/patches/server/0679-Fix-new-block-data-for-EntityChangeBlockEvent.patch +++ /dev/null @@ -1,215 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SoSeDiK -Date: Mon, 21 Mar 2022 20:00:53 +0200 -Subject: [PATCH] Fix new block data for EntityChangeBlockEvent - -Also standardizes how to handle EntityChangeBlockEvent before a removeBlock or destroyBlock -call. Always use 'state.getFluidState().createLegacyBlock()' to get the new state instead of -just using the 'air' state. - -Also fixes the new block data for EntityBreakDoorEvent (a sub-event from -EntityChangeBlockEvent) - -Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -index 6a7052cd6ec88ed4aaea2fef0ebc750060d1dec0..2ade08d1466660ee1787fa97908002ef56389712 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -@@ -108,7 +108,7 @@ public class HarvestFarmland extends Behavior { - Block block1 = world.getBlockState(this.aboveFarmlandPos.below()).getBlock(); - - if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata)) { -- if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, Blocks.AIR.defaultBlockState())) { // CraftBukkit -+ if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state - world.destroyBlock(this.aboveFarmlandPos, true, entity); - } // CraftBukkit - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -index e2aa6d46375cbc4f4b694888c4f9750eb26e4940..6827426e6e9706909265f84bf97b5fa7105a7fea 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -@@ -73,7 +73,7 @@ public class BreakDoorGoal extends DoorInteractGoal { - - if (this.breakTime == this.getDoorBreakTime() && this.isValidDifficulty(this.mob.level().getDifficulty())) { - // CraftBukkit start -- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.mob, this.doorPos).isCancelled()) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.mob, this.doorPos, this.mob.level().getFluidState(this.doorPos).createLegacyBlock()).isCancelled()) { // Paper - fix wrong block state - this.start(); - return; - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -index dc3602002e60d64cbbe9504c22282a9e65da2c9d..9e6f946e6d2878aa3fa8abe0f6fa4770d18676d3 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -@@ -67,8 +67,9 @@ public class EatBlockGoal extends Goal { - if (this.eatAnimationTick == this.adjustedTickDelay(4)) { - BlockPos blockposition = this.mob.blockPosition(); - -- if (EatBlockGoal.IS_TALL_GRASS.test(this.level.getBlockState(blockposition))) { -- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, Blocks.AIR.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit -+ final BlockState blockState = this.level.getBlockState(blockposition); // Paper - fix wrong block state -+ if (EatBlockGoal.IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state -+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state - this.level.destroyBlock(blockposition, false); - } - -@@ -77,7 +78,7 @@ public class EatBlockGoal extends Goal { - BlockPos blockposition1 = blockposition.below(); - - if (this.level.getBlockState(blockposition1).is(Blocks.GRASS_BLOCK)) { -- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.AIR.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit -+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state - this.level.levelEvent(2001, blockposition1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState())); - this.level.setBlock(blockposition1, Blocks.DIRT.defaultBlockState(), 2); - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -index a2bbb79f2999e719b8c80d33e530391ec3d1d2d2..8cc6022507c97af62fb2b4455198bc35744137c9 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -@@ -580,7 +580,7 @@ public class Rabbit extends Animal implements VariantHolder { - - if (i == 0) { - // CraftBukkit start -- if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, Blocks.AIR.defaultBlockState())) { -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - return; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index b145023308e6a2823d83db97ff2d79c38b709ef9..e6b18d7f8922cb42acb9e40bef2f71a56aea8646 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -375,7 +375,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { - - if (WitherBoss.canDestroy(iblockdata)) { - // CraftBukkit start -- if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, Blocks.AIR.defaultBlockState())) { -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - continue; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 0e8349aa6cb23860a4dd884e730ac8f22d422205..48dcd2bc12ce1d08cc5195bff5460dc0dd9902d3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -552,7 +552,7 @@ public class EnderMan extends Monster implements NeutralMob { - boolean flag = movingobjectpositionblock.getBlockPos().equals(blockposition); - - if (iblockdata.is(BlockTags.ENDERMAN_HOLDABLE) && flag) { -- if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, Blocks.AIR.defaultBlockState())) { // CraftBukkit - Place event -+ if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit - Place event // Paper - fix wrong block state - world.removeBlock(blockposition, false); - world.gameEvent((Holder) GameEvent.BLOCK_DESTROY, blockposition, GameEvent.Context.of(this.enderman, iblockdata)); - this.enderman.setCarriedBlock(iblockdata.getBlock().defaultBlockState()); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index c661ae4e5c07494c7de852cc8d01f0f9839c1590..c96fbfe448b3e7b722a8db0e1688276776abd94e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -165,7 +165,7 @@ public class Ravager extends Raider { - - if (block instanceof LeavesBlock) { - // CraftBukkit start -- if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - continue; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java -index 52d8ea3e40cdb01eab428f5d3d945c0c9f6088ce..ff65cb8ea5233f2dd159f42ad53bc9d300cd604f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java -@@ -165,7 +165,8 @@ public class Silverfish extends Monster { - - if (block instanceof InfestedBlock) { - // CraftBukkit start -- if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { -+ BlockState afterState = getServerLevel(world).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? iblockdata.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1)); // Paper - fix wrong block state -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, afterState)) { // Paper - fix wrong block state - continue; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -index a486466040a646b8a5a5ff2430cdd25b95b7e20f..e78eef3b6fbcd657f9dd180df4cb2eeb55d0814f 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -@@ -294,7 +294,7 @@ public class ThrownPotion extends ThrowableItemProjectile { - - if (iblockdata.is(BlockTags.FIRE)) { - // CraftBukkit start -- if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, Blocks.AIR.defaultBlockState())) { -+ if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - this.level().destroyBlock(pos, false, this); - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java b/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java -index fae574f8617bada96469a2eb1349eaa061f0450f..6d0d13e70a82c4db7848e1007f5b6d670dd5acad 100644 ---- a/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java -@@ -286,7 +286,7 @@ public class ChorusFlowerBlock extends Block { - if (world instanceof ServerLevel worldserver) { - if (projectile.mayInteract(worldserver, blockposition) && projectile.mayBreak(worldserver)) { - // CraftBukkit -- if (!CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState())) { -+ if (!CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - return; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -index 48503f5ba8bccb42ae3b5324a5f65f6c23a8e479..bd38a0a73d543a85bb5c6d50219f5438ce194df3 100644 ---- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -@@ -137,7 +137,7 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate - - if (projectile.mayInteract(worldserver, blockposition) && projectile.mayBreak(worldserver) && projectile instanceof ThrownTrident && projectile.getDeltaMovement().length() > 0.6D) { - // CraftBukkit start -- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState())) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - return; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/TntBlock.java b/src/main/java/net/minecraft/world/level/block/TntBlock.java -index d256b0f3998028709334dd6c394d184f2c36efce..2cbe2053dd5d0bcdcd89de69762c77b400b8697a 100644 ---- a/src/main/java/net/minecraft/world/level/block/TntBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TntBlock.java -@@ -158,7 +158,7 @@ public class TntBlock extends Block { - - if (projectile.isOnFire() && projectile.mayInteract(worldserver, blockposition)) { - // CraftBukkit start -- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState()) || !CraftEventFactory.callTNTPrimeEvent(world, blockposition, PrimeCause.PROJECTILE, projectile, null)) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock()) || !CraftEventFactory.callTNTPrimeEvent(world, blockposition, PrimeCause.PROJECTILE, projectile, null)) { // Paper - fix wrong block state - return; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java -index 674d710ff88db5eced9e017284d1b7ec7a4fe7cd..72320c6099a4b26235bab68570e7b7efad84740f 100644 ---- a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java -@@ -37,7 +37,7 @@ public class WaterlilyBlock extends BushBlock { - super.entityInside(state, world, pos, entity); - if (world instanceof ServerLevel && entity instanceof AbstractBoat) { - // CraftBukkit start -- if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState())) { -+ if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - return; - } - // CraftBukkit end -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index e0418c0c36aa99ea43dbf39fa176ddf8855e0568..f54a4c263eeb4df40c72c20c3c480ce74718a718 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1378,11 +1378,11 @@ public class CraftEventFactory { - return event; - } - -- public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos) { -+ public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos, net.minecraft.world.level.block.state.BlockState newState) { // Paper - org.bukkit.entity.Entity entity1 = entity.getBukkitEntity(); - Block block = CraftBlock.at(entity.level(), pos); - -- EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block); -+ EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block, newState.createCraftBlockData()); // Paper - entity1.getServer().getPluginManager().callEvent(event); - - return event; diff --git a/patches/server/0679-fix-player-loottables-running-when-mob-loot-gamerule.patch b/patches/server/0679-fix-player-loottables-running-when-mob-loot-gamerule.patch new file mode 100644 index 0000000000..7a7f077e66 --- /dev/null +++ b/patches/server/0679-fix-player-loottables-running-when-mob-loot-gamerule.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 22 Mar 2022 09:50:40 -0700 +Subject: [PATCH] fix player loottables running when mob loot gamerule is false + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index f72ab5e4e743cb0758ebca28e81f97c143c91b42..d723adaa7b1df4a1d5067298536b303992ac2c52 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1218,12 +1218,14 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } + } + } ++ if (this.shouldDropLoot() && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false + // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule) + this.dropFromLootTable(this.serverLevel(), damageSource, this.lastHurtByPlayerTime > 0); + this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag); + + loot.addAll(this.drops); + this.drops.clear(); // SPIGOT-5188: make sure to clear ++ } // Paper - fix player loottables running when mob loot gamerule is false + + Component defaultMessage = this.getCombatTracker().getDeathMessage(); + diff --git a/patches/server/0680-Ensure-entity-passenger-world-matches-ridden-entity.patch b/patches/server/0680-Ensure-entity-passenger-world-matches-ridden-entity.patch new file mode 100644 index 0000000000..62372a6087 --- /dev/null +++ b/patches/server/0680-Ensure-entity-passenger-world-matches-ridden-entity.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Thu, 31 Mar 2022 05:11:37 -0700 +Subject: [PATCH] Ensure entity passenger world matches ridden entity + +Bad plugins doing this would cause some obvious problems... + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 4f9ebf7a577223d85ceaad0babd2d0b4f492b6df..a4a07dc11edf3738698deed929cc224ff7114684 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2802,7 +2802,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public boolean startRiding(Entity entity, boolean force) { +- if (entity == this.vehicle) { ++ if (entity == this.vehicle || entity.level != this.level) { // Paper - Ensure entity passenger world matches ridden entity (bad plugins) + return false; + } else if (!entity.couldAcceptPassenger()) { + return false; diff --git a/patches/server/0680-fix-player-loottables-running-when-mob-loot-gamerule.patch b/patches/server/0680-fix-player-loottables-running-when-mob-loot-gamerule.patch deleted file mode 100644 index 7a7f077e66..0000000000 --- a/patches/server/0680-fix-player-loottables-running-when-mob-loot-gamerule.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 22 Mar 2022 09:50:40 -0700 -Subject: [PATCH] fix player loottables running when mob loot gamerule is false - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index f72ab5e4e743cb0758ebca28e81f97c143c91b42..d723adaa7b1df4a1d5067298536b303992ac2c52 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1218,12 +1218,14 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } - } - } -+ if (this.shouldDropLoot() && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false - // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule) - this.dropFromLootTable(this.serverLevel(), damageSource, this.lastHurtByPlayerTime > 0); - this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag); - - loot.addAll(this.drops); - this.drops.clear(); // SPIGOT-5188: make sure to clear -+ } // Paper - fix player loottables running when mob loot gamerule is false - - Component defaultMessage = this.getCombatTracker().getDeathMessage(); - diff --git a/patches/server/0681-Cache-resource-keys-and-optimize-reference-Holder-ta.patch b/patches/server/0681-Cache-resource-keys-and-optimize-reference-Holder-ta.patch new file mode 100644 index 0000000000..263f5852b3 --- /dev/null +++ b/patches/server/0681-Cache-resource-keys-and-optimize-reference-Holder-ta.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 20 Mar 2022 22:06:47 -0700 +Subject: [PATCH] Cache resource keys and optimize reference Holder tags set + +TagKeys are always interned, so we can use a reference hash set for them + +diff --git a/src/main/java/net/minecraft/core/Holder.java b/src/main/java/net/minecraft/core/Holder.java +index 94671ea227b59a8f820425c401712e6aeb8b2b10..e91c4e26c25980645941ca8fbdcc3a9d02e31063 100644 +--- a/src/main/java/net/minecraft/core/Holder.java ++++ b/src/main/java/net/minecraft/core/Holder.java +@@ -230,7 +230,7 @@ public interface Holder { + } + + void bindTags(Collection> tags) { +- this.tags = Set.copyOf(tags); ++ this.tags = java.util.Collections.unmodifiableSet(new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(tags)); // Paper + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java +index 95b956802f83b583a823fcd24808363775a56842..33d2e89ac40465b0c4633f9c51378b80f7c397a9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java +@@ -3,6 +3,7 @@ package org.bukkit.craftbukkit.block; + import com.google.common.base.Preconditions; + import net.minecraft.core.Holder; + import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceKey; + import org.bukkit.Registry; + import org.bukkit.block.Biome; + import org.bukkit.craftbukkit.CraftRegistry; +@@ -27,13 +28,14 @@ public class CraftBiome { + return CraftBiome.minecraftToBukkit(minecraft.value()); + } + ++ private static final java.util.Map> BIOME_KEY_CACHE = java.util.Collections.synchronizedMap(new java.util.EnumMap<>(Biome.class)); // Paper + public static net.minecraft.world.level.biome.Biome bukkitToMinecraft(Biome bukkit) { + if (bukkit == null || bukkit == Biome.CUSTOM) { + return null; + } + + return CraftRegistry.getMinecraftRegistry(Registries.BIOME) +- .getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow(); ++ .getOptional(BIOME_KEY_CACHE.computeIfAbsent(bukkit, b -> ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(b.getKey())))).orElseThrow(); + } + + public static Holder bukkitToMinecraftHolder(Biome bukkit) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java +index 6cf8af0c85231de9955282d4abaa0607ec9a195c..d230cbc26f61d8ac5880825aca4dfab197c20401 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java +@@ -25,11 +25,11 @@ public class CraftEntityType { + return bukkit; + } + ++ private static final java.util.Map>> KEY_CACHE = java.util.Collections.synchronizedMap(new java.util.EnumMap<>(EntityType.class)); // Paper + public static net.minecraft.world.entity.EntityType bukkitToMinecraft(EntityType bukkit) { + Preconditions.checkArgument(bukkit != null); +- + return CraftRegistry.getMinecraftRegistry(Registries.ENTITY_TYPE) +- .getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow(); ++ .getOptional(KEY_CACHE.computeIfAbsent(bukkit, type -> net.minecraft.resources.ResourceKey.create(Registries.ENTITY_TYPE, CraftNamespacedKey.toMinecraft(type.getKey())))).orElseThrow(); + } + + public static Holder> bukkitToMinecraftHolder(EntityType bukkit) { diff --git a/patches/server/0681-Ensure-entity-passenger-world-matches-ridden-entity.patch b/patches/server/0681-Ensure-entity-passenger-world-matches-ridden-entity.patch deleted file mode 100644 index 62372a6087..0000000000 --- a/patches/server/0681-Ensure-entity-passenger-world-matches-ridden-entity.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 31 Mar 2022 05:11:37 -0700 -Subject: [PATCH] Ensure entity passenger world matches ridden entity - -Bad plugins doing this would cause some obvious problems... - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 4f9ebf7a577223d85ceaad0babd2d0b4f492b6df..a4a07dc11edf3738698deed929cc224ff7114684 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2802,7 +2802,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public boolean startRiding(Entity entity, boolean force) { -- if (entity == this.vehicle) { -+ if (entity == this.vehicle || entity.level != this.level) { // Paper - Ensure entity passenger world matches ridden entity (bad plugins) - return false; - } else if (!entity.couldAcceptPassenger()) { - return false; diff --git a/patches/server/0682-Allow-changing-the-EnderDragon-podium.patch b/patches/server/0682-Allow-changing-the-EnderDragon-podium.patch new file mode 100644 index 0000000000..5cbce2b4ec --- /dev/null +++ b/patches/server/0682-Allow-changing-the-EnderDragon-podium.patch @@ -0,0 +1,142 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Doc +Date: Sun, 3 Apr 2022 11:31:42 -0400 +Subject: [PATCH] Allow changing the EnderDragon podium + + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +index 25d2226c2a5dda411a9e35f7a0e3ab183110c227..38456d3901e495e4c401cff0de7ae38544c1b2a7 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +@@ -104,6 +104,10 @@ public class EnderDragon extends Mob implements Enemy { + private final int[] nodeAdjacency; + private final BinaryHeap openSet; + private final Explosion explosionSource; // CraftBukkit - reusable source for CraftTNTPrimed.getSource() ++ // Paper start - Allow changing the EnderDragon podium ++ @Nullable ++ private BlockPos podium; ++ // Paper end - Allow changing the EnderDragon podium + + public EnderDragon(EntityType entitytypes, Level world) { + super(EntityType.ENDER_DRAGON, world); +@@ -143,6 +147,19 @@ public class EnderDragon extends Mob implements Enemy { + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D); + } + ++ // Paper start - Allow changing the EnderDragon podium ++ public BlockPos getPodium() { ++ if (this.podium == null) { ++ return EndPodiumFeature.getLocation(this.getFightOrigin()); ++ } ++ return this.podium; ++ } ++ ++ public void setPodium(@Nullable BlockPos blockPos) { ++ this.podium = blockPos; ++ } ++ // Paper end - Allow changing the EnderDragon podium ++ + @Override + public boolean isFlapping() { + float f = Mth.cos(this.flapTime * 6.2831855F); +@@ -988,7 +1005,7 @@ public class EnderDragon extends Mob implements Enemy { + vec3d = this.getViewVector(tickDelta); + } + } else { +- BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin)); ++ BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium + + f1 = Math.max((float) Math.sqrt(blockposition.distToCenterSqr(this.position())) / 4.0F, 1.0F); + float f3 = 6.0F / f1; +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java +index a897c994423d7d624df6ff3a67789cc2436f0417..29f4acc2943ce009088c61bb32aed330f6e2c051 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java +@@ -42,7 +42,7 @@ public class DragonDeathPhase extends AbstractDragonPhaseInstance { + public void doServerTick(ServerLevel world) { + this.time++; + if (this.targetLocation == null) { +- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + this.targetLocation = Vec3.atBottomCenterOf(blockPos); + } + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java +index 2db996f3528c65f5d719cbcfb8ae587ff59c14c1..8e39cf181993ff284a2b0429577de0c307f3ef16 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java +@@ -53,7 +53,7 @@ public class DragonHoldingPatternPhase extends AbstractDragonPhaseInstance { + + private void findNewTarget(ServerLevel world) { + if (this.currentPath != null && this.currentPath.isDone()) { +- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + int i = this.dragon.getDragonFight() == null ? 0 : this.dragon.getDragonFight().getCrystalsAlive(); + if (this.dragon.getRandom().nextInt(i + 3) == 0) { + this.dragon.getPhaseManager().setPhase(EnderDragonPhase.LANDING_APPROACH); +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java +index 4c28d3c3d601b5316d79c8474d106800abc8e95b..1c4250cc61b770707ad25c0e93caeacbcb0a80b0 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java +@@ -52,7 +52,7 @@ public class DragonLandingApproachPhase extends AbstractDragonPhaseInstance { + private void findNewTarget(ServerLevel world) { + if (this.currentPath == null || this.currentPath.isDone()) { + int i = this.dragon.findClosestNode(); +- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + Player player = world.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, (double)blockPos.getX(), (double)blockPos.getY(), (double)blockPos.getZ()); + int j; + if (player != null) { +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java +index 789df0e05d0cf0df0f66bffc98f587a31770ebea..cfcd3f91517832d26c1177c3715cfa8ebe675193 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java +@@ -42,7 +42,7 @@ public class DragonLandingPhase extends AbstractDragonPhaseInstance { + public void doServerTick(ServerLevel world) { + if (this.targetLocation == null) { + this.targetLocation = Vec3.atBottomCenterOf( +- world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())) ++ world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()) // Paper - Allow changing the EnderDragon podium + ); + } + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java +index f942ea2ad87d4ae12921578f7b869f064c8db7b0..5c5b03f612621ec4efd92b78601032b84e6f3c28 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java +@@ -24,7 +24,7 @@ public class DragonTakeoffPhase extends AbstractDragonPhaseInstance { + @Override + public void doServerTick(ServerLevel world) { + if (!this.firstTick && this.currentPath != null) { +- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + if (!blockPos.closerToCenterThan(this.dragon.position(), 10.0)) { + this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java +index 25b3d889a1742c347e60725df8d6f6c1cee264c7..7b7b89e67d53ed70efae714192c5fa32977f3d9c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java +@@ -73,4 +73,22 @@ public class CraftEnderDragon extends CraftMob implements EnderDragon, CraftEnem + public int getDeathAnimationTicks() { + return this.getHandle().dragonDeathTime; + } ++ ++ // Paper start - Allow changing the EnderDragon podium ++ @Override ++ public org.bukkit.Location getPodium() { ++ net.minecraft.core.BlockPos blockPosOrigin = this.getHandle().getPodium(); ++ return new org.bukkit.Location(getWorld(), blockPosOrigin.getX(), blockPosOrigin.getY(), blockPosOrigin.getZ()); ++ } ++ ++ @Override ++ public void setPodium(org.bukkit.Location location) { ++ if (location == null) { ++ this.getHandle().setPodium(null); ++ } else { ++ org.apache.commons.lang.Validate.isTrue(location.getWorld() == null || location.getWorld().equals(getWorld()), "You cannot set a podium in a different world to where the dragon is"); ++ this.getHandle().setPodium(io.papermc.paper.util.MCUtil.toBlockPos(location)); ++ } ++ } ++ // Paper end - Allow changing the EnderDragon podium + } diff --git a/patches/server/0682-Cache-resource-keys-and-optimize-reference-Holder-ta.patch b/patches/server/0682-Cache-resource-keys-and-optimize-reference-Holder-ta.patch deleted file mode 100644 index 263f5852b3..0000000000 --- a/patches/server/0682-Cache-resource-keys-and-optimize-reference-Holder-ta.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 20 Mar 2022 22:06:47 -0700 -Subject: [PATCH] Cache resource keys and optimize reference Holder tags set - -TagKeys are always interned, so we can use a reference hash set for them - -diff --git a/src/main/java/net/minecraft/core/Holder.java b/src/main/java/net/minecraft/core/Holder.java -index 94671ea227b59a8f820425c401712e6aeb8b2b10..e91c4e26c25980645941ca8fbdcc3a9d02e31063 100644 ---- a/src/main/java/net/minecraft/core/Holder.java -+++ b/src/main/java/net/minecraft/core/Holder.java -@@ -230,7 +230,7 @@ public interface Holder { - } - - void bindTags(Collection> tags) { -- this.tags = Set.copyOf(tags); -+ this.tags = java.util.Collections.unmodifiableSet(new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(tags)); // Paper - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java -index 95b956802f83b583a823fcd24808363775a56842..33d2e89ac40465b0c4633f9c51378b80f7c397a9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java -@@ -3,6 +3,7 @@ package org.bukkit.craftbukkit.block; - import com.google.common.base.Preconditions; - import net.minecraft.core.Holder; - import net.minecraft.core.registries.Registries; -+import net.minecraft.resources.ResourceKey; - import org.bukkit.Registry; - import org.bukkit.block.Biome; - import org.bukkit.craftbukkit.CraftRegistry; -@@ -27,13 +28,14 @@ public class CraftBiome { - return CraftBiome.minecraftToBukkit(minecraft.value()); - } - -+ private static final java.util.Map> BIOME_KEY_CACHE = java.util.Collections.synchronizedMap(new java.util.EnumMap<>(Biome.class)); // Paper - public static net.minecraft.world.level.biome.Biome bukkitToMinecraft(Biome bukkit) { - if (bukkit == null || bukkit == Biome.CUSTOM) { - return null; - } - - return CraftRegistry.getMinecraftRegistry(Registries.BIOME) -- .getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow(); -+ .getOptional(BIOME_KEY_CACHE.computeIfAbsent(bukkit, b -> ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(b.getKey())))).orElseThrow(); - } - - public static Holder bukkitToMinecraftHolder(Biome bukkit) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java -index 6cf8af0c85231de9955282d4abaa0607ec9a195c..d230cbc26f61d8ac5880825aca4dfab197c20401 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java -@@ -25,11 +25,11 @@ public class CraftEntityType { - return bukkit; - } - -+ private static final java.util.Map>> KEY_CACHE = java.util.Collections.synchronizedMap(new java.util.EnumMap<>(EntityType.class)); // Paper - public static net.minecraft.world.entity.EntityType bukkitToMinecraft(EntityType bukkit) { - Preconditions.checkArgument(bukkit != null); -- - return CraftRegistry.getMinecraftRegistry(Registries.ENTITY_TYPE) -- .getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow(); -+ .getOptional(KEY_CACHE.computeIfAbsent(bukkit, type -> net.minecraft.resources.ResourceKey.create(Registries.ENTITY_TYPE, CraftNamespacedKey.toMinecraft(type.getKey())))).orElseThrow(); - } - - public static Holder> bukkitToMinecraftHolder(EntityType bukkit) { diff --git a/patches/server/0683-Allow-changing-the-EnderDragon-podium.patch b/patches/server/0683-Allow-changing-the-EnderDragon-podium.patch deleted file mode 100644 index 5cbce2b4ec..0000000000 --- a/patches/server/0683-Allow-changing-the-EnderDragon-podium.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Doc -Date: Sun, 3 Apr 2022 11:31:42 -0400 -Subject: [PATCH] Allow changing the EnderDragon podium - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index 25d2226c2a5dda411a9e35f7a0e3ab183110c227..38456d3901e495e4c401cff0de7ae38544c1b2a7 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -@@ -104,6 +104,10 @@ public class EnderDragon extends Mob implements Enemy { - private final int[] nodeAdjacency; - private final BinaryHeap openSet; - private final Explosion explosionSource; // CraftBukkit - reusable source for CraftTNTPrimed.getSource() -+ // Paper start - Allow changing the EnderDragon podium -+ @Nullable -+ private BlockPos podium; -+ // Paper end - Allow changing the EnderDragon podium - - public EnderDragon(EntityType entitytypes, Level world) { - super(EntityType.ENDER_DRAGON, world); -@@ -143,6 +147,19 @@ public class EnderDragon extends Mob implements Enemy { - return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D); - } - -+ // Paper start - Allow changing the EnderDragon podium -+ public BlockPos getPodium() { -+ if (this.podium == null) { -+ return EndPodiumFeature.getLocation(this.getFightOrigin()); -+ } -+ return this.podium; -+ } -+ -+ public void setPodium(@Nullable BlockPos blockPos) { -+ this.podium = blockPos; -+ } -+ // Paper end - Allow changing the EnderDragon podium -+ - @Override - public boolean isFlapping() { - float f = Mth.cos(this.flapTime * 6.2831855F); -@@ -988,7 +1005,7 @@ public class EnderDragon extends Mob implements Enemy { - vec3d = this.getViewVector(tickDelta); - } - } else { -- BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin)); -+ BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium - - f1 = Math.max((float) Math.sqrt(blockposition.distToCenterSqr(this.position())) / 4.0F, 1.0F); - float f3 = 6.0F / f1; -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java -index a897c994423d7d624df6ff3a67789cc2436f0417..29f4acc2943ce009088c61bb32aed330f6e2c051 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java -@@ -42,7 +42,7 @@ public class DragonDeathPhase extends AbstractDragonPhaseInstance { - public void doServerTick(ServerLevel world) { - this.time++; - if (this.targetLocation == null) { -- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - this.targetLocation = Vec3.atBottomCenterOf(blockPos); - } - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java -index 2db996f3528c65f5d719cbcfb8ae587ff59c14c1..8e39cf181993ff284a2b0429577de0c307f3ef16 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java -@@ -53,7 +53,7 @@ public class DragonHoldingPatternPhase extends AbstractDragonPhaseInstance { - - private void findNewTarget(ServerLevel world) { - if (this.currentPath != null && this.currentPath.isDone()) { -- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - int i = this.dragon.getDragonFight() == null ? 0 : this.dragon.getDragonFight().getCrystalsAlive(); - if (this.dragon.getRandom().nextInt(i + 3) == 0) { - this.dragon.getPhaseManager().setPhase(EnderDragonPhase.LANDING_APPROACH); -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java -index 4c28d3c3d601b5316d79c8474d106800abc8e95b..1c4250cc61b770707ad25c0e93caeacbcb0a80b0 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java -@@ -52,7 +52,7 @@ public class DragonLandingApproachPhase extends AbstractDragonPhaseInstance { - private void findNewTarget(ServerLevel world) { - if (this.currentPath == null || this.currentPath.isDone()) { - int i = this.dragon.findClosestNode(); -- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - Player player = world.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, (double)blockPos.getX(), (double)blockPos.getY(), (double)blockPos.getZ()); - int j; - if (player != null) { -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java -index 789df0e05d0cf0df0f66bffc98f587a31770ebea..cfcd3f91517832d26c1177c3715cfa8ebe675193 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java -@@ -42,7 +42,7 @@ public class DragonLandingPhase extends AbstractDragonPhaseInstance { - public void doServerTick(ServerLevel world) { - if (this.targetLocation == null) { - this.targetLocation = Vec3.atBottomCenterOf( -- world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())) -+ world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()) // Paper - Allow changing the EnderDragon podium - ); - } - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java -index f942ea2ad87d4ae12921578f7b869f064c8db7b0..5c5b03f612621ec4efd92b78601032b84e6f3c28 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java -@@ -24,7 +24,7 @@ public class DragonTakeoffPhase extends AbstractDragonPhaseInstance { - @Override - public void doServerTick(ServerLevel world) { - if (!this.firstTick && this.currentPath != null) { -- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - if (!blockPos.closerToCenterThan(this.dragon.position(), 10.0)) { - this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java -index 25b3d889a1742c347e60725df8d6f6c1cee264c7..7b7b89e67d53ed70efae714192c5fa32977f3d9c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java -@@ -73,4 +73,22 @@ public class CraftEnderDragon extends CraftMob implements EnderDragon, CraftEnem - public int getDeathAnimationTicks() { - return this.getHandle().dragonDeathTime; - } -+ -+ // Paper start - Allow changing the EnderDragon podium -+ @Override -+ public org.bukkit.Location getPodium() { -+ net.minecraft.core.BlockPos blockPosOrigin = this.getHandle().getPodium(); -+ return new org.bukkit.Location(getWorld(), blockPosOrigin.getX(), blockPosOrigin.getY(), blockPosOrigin.getZ()); -+ } -+ -+ @Override -+ public void setPodium(org.bukkit.Location location) { -+ if (location == null) { -+ this.getHandle().setPodium(null); -+ } else { -+ org.apache.commons.lang.Validate.isTrue(location.getWorld() == null || location.getWorld().equals(getWorld()), "You cannot set a podium in a different world to where the dragon is"); -+ this.getHandle().setPodium(io.papermc.paper.util.MCUtil.toBlockPos(location)); -+ } -+ } -+ // Paper end - Allow changing the EnderDragon podium - } diff --git a/patches/server/0683-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch b/patches/server/0683-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch new file mode 100644 index 0000000000..f885dbe8b4 --- /dev/null +++ b/patches/server/0683-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: etil2jz +Date: Sat, 2 Apr 2022 23:29:24 +0200 +Subject: [PATCH] Fix NBT pieces overriding a block entity during worldgen + deadlock + +By checking if the world passed into StructureTemplate's placeInWorld +is not a WorldGenRegion, we can bypass the deadlock entirely. +See https://bugs.mojang.com/browse/MC-246262 + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +index b120949667ae0169a667b329b3cabbd79a0a5bda..734f511d197bc6bf2b02588069eb02c0224781f5 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +@@ -303,7 +303,11 @@ public class StructureTemplate { + + if (definedstructure_blockinfo.nbt != null) { + tileentity = world.getBlockEntity(blockposition2); +- Clearable.tryClear(tileentity); ++ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock ++ if (!(world instanceof net.minecraft.world.level.WorldGenLevel)) { ++ Clearable.tryClear(tileentity); ++ } ++ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock + world.setBlock(blockposition2, Blocks.BARRIER.defaultBlockState(), 20); + } + // CraftBukkit start +@@ -430,7 +434,11 @@ public class StructureTemplate { + if (pair1.getSecond() != null) { + tileentity = world.getBlockEntity(blockposition6); + if (tileentity != null) { +- tileentity.setChanged(); ++ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock ++ if (!(world instanceof net.minecraft.world.level.WorldGenLevel)) { ++ tileentity.setChanged(); ++ } ++ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock + } + } + } diff --git a/patches/server/0684-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch b/patches/server/0684-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch deleted file mode 100644 index f885dbe8b4..0000000000 --- a/patches/server/0684-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: etil2jz -Date: Sat, 2 Apr 2022 23:29:24 +0200 -Subject: [PATCH] Fix NBT pieces overriding a block entity during worldgen - deadlock - -By checking if the world passed into StructureTemplate's placeInWorld -is not a WorldGenRegion, we can bypass the deadlock entirely. -See https://bugs.mojang.com/browse/MC-246262 - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -index b120949667ae0169a667b329b3cabbd79a0a5bda..734f511d197bc6bf2b02588069eb02c0224781f5 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -@@ -303,7 +303,11 @@ public class StructureTemplate { - - if (definedstructure_blockinfo.nbt != null) { - tileentity = world.getBlockEntity(blockposition2); -- Clearable.tryClear(tileentity); -+ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock -+ if (!(world instanceof net.minecraft.world.level.WorldGenLevel)) { -+ Clearable.tryClear(tileentity); -+ } -+ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock - world.setBlock(blockposition2, Blocks.BARRIER.defaultBlockState(), 20); - } - // CraftBukkit start -@@ -430,7 +434,11 @@ public class StructureTemplate { - if (pair1.getSecond() != null) { - tileentity = world.getBlockEntity(blockposition6); - if (tileentity != null) { -- tileentity.setChanged(); -+ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock -+ if (!(world instanceof net.minecraft.world.level.WorldGenLevel)) { -+ tileentity.setChanged(); -+ } -+ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock - } - } - } diff --git a/patches/server/0684-Prevent-tile-entity-copies-loading-chunks.patch b/patches/server/0684-Prevent-tile-entity-copies-loading-chunks.patch new file mode 100644 index 0000000000..d690eb7288 --- /dev/null +++ b/patches/server/0684-Prevent-tile-entity-copies-loading-chunks.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Wed, 13 Apr 2022 08:25:42 +0100 +Subject: [PATCH] Prevent tile entity copies loading chunks + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 9656e15aa15735e9bd6ac4e2ad7aa8aa66140b9a..bc8f9bd50de3894e6262e13ed55252c98f22ed8a 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3245,7 +3245,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + BlockPos blockposition = BlockEntity.getPosFromTag(customdata.getUnsafe()); + + if (this.player.level().isLoaded(blockposition)) { +- BlockEntity tileentity = this.player.level().getBlockEntity(blockposition); ++ // Paper start - Prevent tile entity copies loading chunks ++ BlockEntity tileentity = null; ++ if (this.player.distanceToSqr(blockposition.getX(), blockposition.getY(), blockposition.getZ()) < 32 * 32 && this.player.serverLevel().isLoadedAndInBounds(blockposition)) { ++ tileentity = this.player.level().getBlockEntity(blockposition); ++ } ++ // Paper end - Prevent tile entity copies loading chunks + + if (tileentity != null) { + tileentity.saveToItem(itemstack, this.player.level().registryAccess()); diff --git a/patches/server/0685-Prevent-tile-entity-copies-loading-chunks.patch b/patches/server/0685-Prevent-tile-entity-copies-loading-chunks.patch deleted file mode 100644 index e679734f77..0000000000 --- a/patches/server/0685-Prevent-tile-entity-copies-loading-chunks.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Wed, 13 Apr 2022 08:25:42 +0100 -Subject: [PATCH] Prevent tile entity copies loading chunks - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 65e0ad4cae47a1912ad12ea1e6eaa3672d4f12e8..ac2ad33a44ce04d9673adc08ff21a167d606e4db 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3248,7 +3248,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - BlockPos blockposition = BlockEntity.getPosFromTag(customdata.getUnsafe()); - - if (this.player.level().isLoaded(blockposition)) { -- BlockEntity tileentity = this.player.level().getBlockEntity(blockposition); -+ // Paper start - Prevent tile entity copies loading chunks -+ BlockEntity tileentity = null; -+ if (this.player.distanceToSqr(blockposition.getX(), blockposition.getY(), blockposition.getZ()) < 32 * 32 && this.player.serverLevel().isLoadedAndInBounds(blockposition)) { -+ tileentity = this.player.level().getBlockEntity(blockposition); -+ } -+ // Paper end - Prevent tile entity copies loading chunks - - if (tileentity != null) { - tileentity.saveToItem(itemstack, this.player.level().registryAccess()); diff --git a/patches/server/0685-Use-username-instead-of-display-name-in-PlayerList-g.patch b/patches/server/0685-Use-username-instead-of-display-name-in-PlayerList-g.patch new file mode 100644 index 0000000000..5603d7b000 --- /dev/null +++ b/patches/server/0685-Use-username-instead-of-display-name-in-PlayerList-g.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Doc +Date: Fri, 15 Apr 2022 17:40:30 -0400 +Subject: [PATCH] Use username instead of display name in + PlayerList#getPlayerStats + + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index f1530fbcaf9913e43143b40117fb7fe63b326d1d..3d741bd09cd2086aa63b77636fe3ecfc55577aad 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1352,7 +1352,7 @@ public abstract class PlayerList { + // CraftBukkit start + public ServerStatsCounter getPlayerStats(ServerPlayer entityhuman) { + ServerStatsCounter serverstatisticmanager = entityhuman.getStats(); +- return serverstatisticmanager == null ? this.getPlayerStats(entityhuman.getUUID(), entityhuman.getDisplayName().getString()) : serverstatisticmanager; ++ return serverstatisticmanager == null ? this.getPlayerStats(entityhuman.getUUID(), entityhuman.getGameProfile().getName()) : serverstatisticmanager; // Paper - use username and not display name + } + + public ServerStatsCounter getPlayerStats(UUID uuid, String displayName) { diff --git a/patches/server/0686-Expand-PlayerItemDamageEvent.patch b/patches/server/0686-Expand-PlayerItemDamageEvent.patch new file mode 100644 index 0000000000..9659c38659 --- /dev/null +++ b/patches/server/0686-Expand-PlayerItemDamageEvent.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HexedHero <6012891+HexedHero@users.noreply.github.com> +Date: Sun, 10 Apr 2022 06:26:32 +0100 +Subject: [PATCH] Expand PlayerItemDamageEvent + + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index a100c7a53b4b1dac0a01ee65418d44297bcdb93f..bcb3a45166e5dd75dd727adf92304b3a75399c8d 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -693,10 +693,11 @@ public final class ItemStack implements DataComponentHolder { + } + + public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent ++ int originalDamage = amount; // Paper - Expand PlayerItemDamageEvent + int j = this.processDurabilityChange(amount, world, player); + // CraftBukkit start + if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent +- PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j); // Paper - Add EntityDamageItemEvent ++ PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j, originalDamage); // Paper - Add EntityDamageItemEvent + event.getPlayer().getServer().getPluginManager().callEvent(event); + + if (j != event.getDamage() || event.isCancelled()) { diff --git a/patches/server/0686-Use-username-instead-of-display-name-in-PlayerList-g.patch b/patches/server/0686-Use-username-instead-of-display-name-in-PlayerList-g.patch deleted file mode 100644 index b4d6c33900..0000000000 --- a/patches/server/0686-Use-username-instead-of-display-name-in-PlayerList-g.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Doc -Date: Fri, 15 Apr 2022 17:40:30 -0400 -Subject: [PATCH] Use username instead of display name in - PlayerList#getPlayerStats - - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 215a3c9839d664f6cfd4c9360338abcf5863799a..0646e435e869b5cc067968feb09ff5c6a979a8a7 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1354,7 +1354,7 @@ public abstract class PlayerList { - // CraftBukkit start - public ServerStatsCounter getPlayerStats(ServerPlayer entityhuman) { - ServerStatsCounter serverstatisticmanager = entityhuman.getStats(); -- return serverstatisticmanager == null ? this.getPlayerStats(entityhuman.getUUID(), entityhuman.getDisplayName().getString()) : serverstatisticmanager; -+ return serverstatisticmanager == null ? this.getPlayerStats(entityhuman.getUUID(), entityhuman.getGameProfile().getName()) : serverstatisticmanager; // Paper - use username and not display name - } - - public ServerStatsCounter getPlayerStats(UUID uuid, String displayName) { diff --git a/patches/server/0687-Expand-PlayerItemDamageEvent.patch b/patches/server/0687-Expand-PlayerItemDamageEvent.patch deleted file mode 100644 index 9659c38659..0000000000 --- a/patches/server/0687-Expand-PlayerItemDamageEvent.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: HexedHero <6012891+HexedHero@users.noreply.github.com> -Date: Sun, 10 Apr 2022 06:26:32 +0100 -Subject: [PATCH] Expand PlayerItemDamageEvent - - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index a100c7a53b4b1dac0a01ee65418d44297bcdb93f..bcb3a45166e5dd75dd727adf92304b3a75399c8d 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -693,10 +693,11 @@ public final class ItemStack implements DataComponentHolder { - } - - public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent -+ int originalDamage = amount; // Paper - Expand PlayerItemDamageEvent - int j = this.processDurabilityChange(amount, world, player); - // CraftBukkit start - if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent -- PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j); // Paper - Add EntityDamageItemEvent -+ PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j, originalDamage); // Paper - Add EntityDamageItemEvent - event.getPlayer().getServer().getPluginManager().callEvent(event); - - if (j != event.getDamage() || event.isCancelled()) { diff --git a/patches/server/0687-WorldCreator-keepSpawnLoaded.patch b/patches/server/0687-WorldCreator-keepSpawnLoaded.patch new file mode 100644 index 0000000000..6712b0e0a3 --- /dev/null +++ b/patches/server/0687-WorldCreator-keepSpawnLoaded.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sat, 3 Jul 2021 21:18:28 +0100 +Subject: [PATCH] WorldCreator#keepSpawnLoaded + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index a504a6458423a997e703e95356dd2058d6c164e2..6ba912570ea66c3b0747beb4c168e351904cc31e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1328,7 +1328,7 @@ public final class CraftServer implements Server { + } + + // If set to not keep spawn in memory (changed from default) then adjust rule accordingly +- if (!creator.keepSpawnInMemory()) { ++ if (creator.keepSpawnLoaded() == net.kyori.adventure.util.TriState.FALSE) { // Paper + worlddata.getGameRules().getRule(GameRules.RULE_SPAWN_CHUNK_RADIUS).set(0, null); + } + ServerLevel internal = (ServerLevel) new ServerLevel(this.console, this.console.executor, worldSession, worlddata, worldKey, worlddimension, this.getServer().progressListenerFactory.create(worlddata.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)), diff --git a/patches/server/0688-Fix-CME-in-CraftPersistentDataTypeRegistry.patch b/patches/server/0688-Fix-CME-in-CraftPersistentDataTypeRegistry.patch new file mode 100644 index 0000000000..ed8adb4503 --- /dev/null +++ b/patches/server/0688-Fix-CME-in-CraftPersistentDataTypeRegistry.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gero +Date: Sat, 2 Oct 2021 20:08:30 +0200 +Subject: [PATCH] Fix CME in CraftPersistentDataTypeRegistry + + +diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java +index 71dc4a2285ddc86e7aa65ba1a211997ffa8fcce4..20c53aac0aef180ee12de919a8000e4b4bc619ff 100644 +--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java +@@ -121,7 +121,7 @@ public final class CraftPersistentDataTypeRegistry { + } + } + +- private final Map adapters = new HashMap<>(); ++ private final Map adapters = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - Replace HashMap with ConcurrentHashMap to avoid CME + + /** + * Creates a suitable adapter instance for the primitive class type. diff --git a/patches/server/0688-WorldCreator-keepSpawnLoaded.patch b/patches/server/0688-WorldCreator-keepSpawnLoaded.patch deleted file mode 100644 index 2b6c3f2d6e..0000000000 --- a/patches/server/0688-WorldCreator-keepSpawnLoaded.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sat, 3 Jul 2021 21:18:28 +0100 -Subject: [PATCH] WorldCreator#keepSpawnLoaded - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 2860aa8f75ec5901023f88047cb4cb96298a99e0..d0a72476d36294792550425a8c0646a7c0be75a7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1329,7 +1329,7 @@ public final class CraftServer implements Server { - } - - // If set to not keep spawn in memory (changed from default) then adjust rule accordingly -- if (!creator.keepSpawnInMemory()) { -+ if (creator.keepSpawnLoaded() == net.kyori.adventure.util.TriState.FALSE) { // Paper - worlddata.getGameRules().getRule(GameRules.RULE_SPAWN_CHUNK_RADIUS).set(0, null); - } - ServerLevel internal = (ServerLevel) new ServerLevel(this.console, this.console.executor, worldSession, worlddata, worldKey, worlddimension, this.getServer().progressListenerFactory.create(worlddata.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)), diff --git a/patches/server/0689-Fix-CME-in-CraftPersistentDataTypeRegistry.patch b/patches/server/0689-Fix-CME-in-CraftPersistentDataTypeRegistry.patch deleted file mode 100644 index ed8adb4503..0000000000 --- a/patches/server/0689-Fix-CME-in-CraftPersistentDataTypeRegistry.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Gero -Date: Sat, 2 Oct 2021 20:08:30 +0200 -Subject: [PATCH] Fix CME in CraftPersistentDataTypeRegistry - - -diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java -index 71dc4a2285ddc86e7aa65ba1a211997ffa8fcce4..20c53aac0aef180ee12de919a8000e4b4bc619ff 100644 ---- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java -@@ -121,7 +121,7 @@ public final class CraftPersistentDataTypeRegistry { - } - } - -- private final Map adapters = new HashMap<>(); -+ private final Map adapters = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - Replace HashMap with ConcurrentHashMap to avoid CME - - /** - * Creates a suitable adapter instance for the primitive class type. diff --git a/patches/server/0689-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch b/patches/server/0689-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch new file mode 100644 index 0000000000..3ecc56a332 --- /dev/null +++ b/patches/server/0689-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Feb 2022 13:50:06 -0800 +Subject: [PATCH] Trigger bee_nest_destroyed trigger in the correct place + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index e000a918230187f6841b03b7b0dd73687f3cc15e..5c3e5c348e6fececccd8097355f423b9e7ad982b 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -427,12 +427,16 @@ public class ServerPlayerGameMode { + block.destroy(this.level, pos, iblockdata1); + } + ++ ItemStack mainHandStack = null; // Paper - Trigger bee_nest_destroyed trigger in the correct place ++ boolean isCorrectTool = false; // Paper - Trigger bee_nest_destroyed trigger in the correct place + if (this.isCreative()) { + // return true; // CraftBukkit + } else { + ItemStack itemstack = this.player.getMainHandItem(); + ItemStack itemstack1 = itemstack.copy(); + boolean flag1 = this.player.hasCorrectToolForDrops(iblockdata1); ++ mainHandStack = itemstack1; // Paper - Trigger bee_nest_destroyed trigger in the correct place ++ isCorrectTool = flag1; // Paper - Trigger bee_nest_destroyed trigger in the correct place + + itemstack.mineBlock(this.level, iblockdata1, pos, this.player); + if (flag && flag1 && event.isDropItems()) { // CraftBukkit - Check if block should drop items +@@ -453,6 +457,13 @@ public class ServerPlayerGameMode { + if (flag && event != null) { + iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper + } ++ // Paper start - Trigger bee_nest_destroyed trigger in the correct place (check impls of block#playerDestroy) ++ if (mainHandStack != null) { ++ if (flag && isCorrectTool && event.isDropItems() && block instanceof net.minecraft.world.level.block.BeehiveBlock && tileentity instanceof net.minecraft.world.level.block.entity.BeehiveBlockEntity beehiveBlockEntity) { // simulates the guard on block#playerDestroy above ++ CriteriaTriggers.BEE_NEST_DESTROYED.trigger(player, iblockdata, mainHandStack, beehiveBlockEntity.getOccupantCount()); ++ } ++ } ++ // Paper end - Trigger bee_nest_destroyed trigger in the correct place + + return true; + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java +index 20f705c90a0a96321cfe29c0cf564013dcccd18f..d5ed53c37bba79f84b60d616887cd5176e124f10 100644 +--- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java +@@ -103,7 +103,7 @@ public class BeehiveBlock extends BaseEntityBlock { + this.angerNearbyBees(world, pos); + } + +- CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer) player, state, tool, tileentitybeehive.getOccupantCount()); ++ // CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer) player, state, tool, tileentitybeehive.getOccupantCount()); // Paper - Trigger bee_nest_destroyed trigger in the correct place; moved until after items are dropped + } + + } diff --git a/patches/server/0690-Add-EntityDyeEvent-and-CollarColorable-interface.patch b/patches/server/0690-Add-EntityDyeEvent-and-CollarColorable-interface.patch new file mode 100644 index 0000000000..d50c55e4e3 --- /dev/null +++ b/patches/server/0690-Add-EntityDyeEvent-and-CollarColorable-interface.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 18 Mar 2022 21:15:55 -0700 +Subject: [PATCH] Add EntityDyeEvent and CollarColorable interface + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java +index 5a86530c65d7d83e4608600a04ffd931bf59dc4a..bffc7c21727a6e5ff13a498aa51f6797e4d6d596 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java +@@ -387,6 +387,13 @@ public class Cat extends TamableAnimal implements VariantHolder -Date: Wed, 2 Feb 2022 13:50:06 -0800 -Subject: [PATCH] Trigger bee_nest_destroyed trigger in the correct place - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index e000a918230187f6841b03b7b0dd73687f3cc15e..5c3e5c348e6fececccd8097355f423b9e7ad982b 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -427,12 +427,16 @@ public class ServerPlayerGameMode { - block.destroy(this.level, pos, iblockdata1); - } - -+ ItemStack mainHandStack = null; // Paper - Trigger bee_nest_destroyed trigger in the correct place -+ boolean isCorrectTool = false; // Paper - Trigger bee_nest_destroyed trigger in the correct place - if (this.isCreative()) { - // return true; // CraftBukkit - } else { - ItemStack itemstack = this.player.getMainHandItem(); - ItemStack itemstack1 = itemstack.copy(); - boolean flag1 = this.player.hasCorrectToolForDrops(iblockdata1); -+ mainHandStack = itemstack1; // Paper - Trigger bee_nest_destroyed trigger in the correct place -+ isCorrectTool = flag1; // Paper - Trigger bee_nest_destroyed trigger in the correct place - - itemstack.mineBlock(this.level, iblockdata1, pos, this.player); - if (flag && flag1 && event.isDropItems()) { // CraftBukkit - Check if block should drop items -@@ -453,6 +457,13 @@ public class ServerPlayerGameMode { - if (flag && event != null) { - iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper - } -+ // Paper start - Trigger bee_nest_destroyed trigger in the correct place (check impls of block#playerDestroy) -+ if (mainHandStack != null) { -+ if (flag && isCorrectTool && event.isDropItems() && block instanceof net.minecraft.world.level.block.BeehiveBlock && tileentity instanceof net.minecraft.world.level.block.entity.BeehiveBlockEntity beehiveBlockEntity) { // simulates the guard on block#playerDestroy above -+ CriteriaTriggers.BEE_NEST_DESTROYED.trigger(player, iblockdata, mainHandStack, beehiveBlockEntity.getOccupantCount()); -+ } -+ } -+ // Paper end - Trigger bee_nest_destroyed trigger in the correct place - - return true; - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -index 20f705c90a0a96321cfe29c0cf564013dcccd18f..d5ed53c37bba79f84b60d616887cd5176e124f10 100644 ---- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -@@ -103,7 +103,7 @@ public class BeehiveBlock extends BaseEntityBlock { - this.angerNearbyBees(world, pos); - } - -- CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer) player, state, tool, tileentitybeehive.getOccupantCount()); -+ // CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer) player, state, tool, tileentitybeehive.getOccupantCount()); // Paper - Trigger bee_nest_destroyed trigger in the correct place; moved until after items are dropped - } - - } diff --git a/patches/server/0691-Add-EntityDyeEvent-and-CollarColorable-interface.patch b/patches/server/0691-Add-EntityDyeEvent-and-CollarColorable-interface.patch deleted file mode 100644 index d50c55e4e3..0000000000 --- a/patches/server/0691-Add-EntityDyeEvent-and-CollarColorable-interface.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 18 Mar 2022 21:15:55 -0700 -Subject: [PATCH] Add EntityDyeEvent and CollarColorable interface - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 5a86530c65d7d83e4608600a04ffd931bf59dc4a..bffc7c21727a6e5ff13a498aa51f6797e4d6d596 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -387,6 +387,13 @@ public class Cat extends TamableAnimal implements VariantHolder +Date: Tue, 29 Mar 2022 13:46:23 -0700 +Subject: [PATCH] Fire CauldronLevelChange on initial fill + +Also don't fire level events or game events if stalactite +drip is cancelled + +diff --git a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java +index 637fef0d3cabc867cf861b507b90221e27a711d1..df76185d42075834a39c79515917e03beb938a06 100644 +--- a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java ++++ b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java +@@ -74,7 +74,7 @@ public interface CauldronInteraction { + if (potioncontents != null && potioncontents.is(Potions.WATER)) { + if (!world.isClientSide) { + // CraftBukkit start +- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { ++ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent + return InteractionResult.SUCCESS; + } + // CraftBukkit end +@@ -129,7 +129,7 @@ public interface CauldronInteraction { + if (potioncontents != null && potioncontents.is(Potions.WATER)) { + if (!world.isClientSide) { + // CraftBukkit start +- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { ++ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent + return InteractionResult.SUCCESS; + } + // CraftBukkit end +@@ -215,7 +215,7 @@ public interface CauldronInteraction { + } else { + if (!world.isClientSide) { + // CraftBukkit start +- if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) { ++ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL, false)) { // Paper - Call CauldronLevelChangeEvent + return InteractionResult.SUCCESS; + } + // CraftBukkit end +@@ -236,7 +236,7 @@ public interface CauldronInteraction { + static InteractionResult emptyBucket(Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, BlockState state, SoundEvent soundEvent) { + if (!world.isClientSide) { + // CraftBukkit start +- if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY)) { ++ if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent + return InteractionResult.SUCCESS; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java +index 8d5ad9848d9652b4fd7179c425c47a683ee169ef..c9968934f4ecaa8d81e545f279b3001c7b1ce545 100644 +--- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java +@@ -44,9 +44,19 @@ public class CauldronBlock extends AbstractCauldronBlock { + public void handlePrecipitation(BlockState state, Level world, BlockPos pos, Biome.Precipitation precipitation) { + if (CauldronBlock.shouldHandlePrecipitation(world, precipitation)) { + if (precipitation == Biome.Precipitation.RAIN) { ++ // Paper start - Call CauldronLevelChangeEvent ++ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.WATER_CAULDRON.defaultBlockState(), null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL, false)) { // avoid duplicate game event ++ return; ++ } ++ // Paper end - Call CauldronLevelChangeEvent + world.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState()); + world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_CHANGE, pos); + } else if (precipitation == Biome.Precipitation.SNOW) { ++ // Paper start - Call CauldronLevelChangeEvent ++ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState(), null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL, false)) { // avoid duplicate game event ++ return; ++ } ++ // Paper end - Call CauldronLevelChangeEvent + world.setBlockAndUpdate(pos, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState()); + world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_CHANGE, pos); + } +@@ -65,11 +75,19 @@ public class CauldronBlock extends AbstractCauldronBlock { + + if (fluid == Fluids.WATER) { + iblockdata1 = Blocks.WATER_CAULDRON.defaultBlockState(); +- LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit ++ // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled ++ if (!LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit ++ return; ++ } ++ // Paper end - Call CauldronLevelChangeEvent + world.levelEvent(1047, pos, 0); + } else if (fluid == Fluids.LAVA) { + iblockdata1 = Blocks.LAVA_CAULDRON.defaultBlockState(); +- LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit ++ // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled ++ if (!LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit ++ return; ++ } ++ // Paper end - Call CauldronLevelChangeEvent + world.levelEvent(1046, pos, 0); + } + +diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java +index 4ab73a083eba2ad3e12526af0a0dbcfba5cf6c14..806d18689126d0a971665a33d7fc91102ec76db5 100644 +--- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java +@@ -107,7 +107,13 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { + } + + // CraftBukkit start +- public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, Entity entity, CauldronLevelChangeEvent.ChangeReason reason) { ++ // Paper start - Call CauldronLevelChangeEvent ++ public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason) { // Paper - entity is nullable ++ return changeLevel(iblockdata, world, blockposition, newBlock, entity, reason, true); ++ } ++ ++ public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason, boolean sendGameEvent) { // Paper - entity is nullable ++ // Paper end - Call CauldronLevelChangeEvent + CraftBlockState newState = CraftBlockStates.getBlockState(world, blockposition); + newState.setData(newBlock); + +@@ -120,7 +126,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { + return false; + } + newState.update(true); +- world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(newBlock)); ++ if (sendGameEvent) world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(newBlock)); // Paper - Call CauldronLevelChangeEvent + return true; + } + // CraftBukkit end diff --git a/patches/server/0692-Fire-CauldronLevelChange-on-initial-fill.patch b/patches/server/0692-Fire-CauldronLevelChange-on-initial-fill.patch deleted file mode 100644 index 86520e0647..0000000000 --- a/patches/server/0692-Fire-CauldronLevelChange-on-initial-fill.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 29 Mar 2022 13:46:23 -0700 -Subject: [PATCH] Fire CauldronLevelChange on initial fill - -Also don't fire level events or game events if stalactite -drip is cancelled - -diff --git a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java -index 637fef0d3cabc867cf861b507b90221e27a711d1..df76185d42075834a39c79515917e03beb938a06 100644 ---- a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java -+++ b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java -@@ -74,7 +74,7 @@ public interface CauldronInteraction { - if (potioncontents != null && potioncontents.is(Potions.WATER)) { - if (!world.isClientSide) { - // CraftBukkit start -- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { -+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent - return InteractionResult.SUCCESS; - } - // CraftBukkit end -@@ -129,7 +129,7 @@ public interface CauldronInteraction { - if (potioncontents != null && potioncontents.is(Potions.WATER)) { - if (!world.isClientSide) { - // CraftBukkit start -- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { -+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent - return InteractionResult.SUCCESS; - } - // CraftBukkit end -@@ -215,7 +215,7 @@ public interface CauldronInteraction { - } else { - if (!world.isClientSide) { - // CraftBukkit start -- if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) { -+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL, false)) { // Paper - Call CauldronLevelChangeEvent - return InteractionResult.SUCCESS; - } - // CraftBukkit end -@@ -236,7 +236,7 @@ public interface CauldronInteraction { - static InteractionResult emptyBucket(Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, BlockState state, SoundEvent soundEvent) { - if (!world.isClientSide) { - // CraftBukkit start -- if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY)) { -+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent - return InteractionResult.SUCCESS; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -index 8d5ad9848d9652b4fd7179c425c47a683ee169ef..c9968934f4ecaa8d81e545f279b3001c7b1ce545 100644 ---- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -@@ -44,9 +44,19 @@ public class CauldronBlock extends AbstractCauldronBlock { - public void handlePrecipitation(BlockState state, Level world, BlockPos pos, Biome.Precipitation precipitation) { - if (CauldronBlock.shouldHandlePrecipitation(world, precipitation)) { - if (precipitation == Biome.Precipitation.RAIN) { -+ // Paper start - Call CauldronLevelChangeEvent -+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.WATER_CAULDRON.defaultBlockState(), null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL, false)) { // avoid duplicate game event -+ return; -+ } -+ // Paper end - Call CauldronLevelChangeEvent - world.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState()); - world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_CHANGE, pos); - } else if (precipitation == Biome.Precipitation.SNOW) { -+ // Paper start - Call CauldronLevelChangeEvent -+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState(), null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL, false)) { // avoid duplicate game event -+ return; -+ } -+ // Paper end - Call CauldronLevelChangeEvent - world.setBlockAndUpdate(pos, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState()); - world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_CHANGE, pos); - } -@@ -65,11 +75,19 @@ public class CauldronBlock extends AbstractCauldronBlock { - - if (fluid == Fluids.WATER) { - iblockdata1 = Blocks.WATER_CAULDRON.defaultBlockState(); -- LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit -+ // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled -+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit -+ return; -+ } -+ // Paper end - Call CauldronLevelChangeEvent - world.levelEvent(1047, pos, 0); - } else if (fluid == Fluids.LAVA) { - iblockdata1 = Blocks.LAVA_CAULDRON.defaultBlockState(); -- LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit -+ // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled -+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit -+ return; -+ } -+ // Paper end - Call CauldronLevelChangeEvent - world.levelEvent(1046, pos, 0); - } - -diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -index 4ab73a083eba2ad3e12526af0a0dbcfba5cf6c14..806d18689126d0a971665a33d7fc91102ec76db5 100644 ---- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -@@ -107,7 +107,13 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { - } - - // CraftBukkit start -- public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, Entity entity, CauldronLevelChangeEvent.ChangeReason reason) { -+ // Paper start - Call CauldronLevelChangeEvent -+ public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason) { // Paper - entity is nullable -+ return changeLevel(iblockdata, world, blockposition, newBlock, entity, reason, true); -+ } -+ -+ public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason, boolean sendGameEvent) { // Paper - entity is nullable -+ // Paper end - Call CauldronLevelChangeEvent - CraftBlockState newState = CraftBlockStates.getBlockState(world, blockposition); - newState.setData(newBlock); - -@@ -120,7 +126,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { - return false; - } - newState.update(true); -- world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(newBlock)); -+ if (sendGameEvent) world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(newBlock)); // Paper - Call CauldronLevelChangeEvent - return true; - } - // CraftBukkit end diff --git a/patches/server/0692-fix-powder-snow-cauldrons-not-turning-to-water.patch b/patches/server/0692-fix-powder-snow-cauldrons-not-turning-to-water.patch new file mode 100644 index 0000000000..201c323a35 --- /dev/null +++ b/patches/server/0692-fix-powder-snow-cauldrons-not-turning-to-water.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 30 Dec 2021 14:02:13 -0800 +Subject: [PATCH] fix powder snow cauldrons not turning to water + +Powder snow cauldrons should turn to water when +extinguishing an entity + +diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java +index 806d18689126d0a971665a33d7fc91102ec76db5..7dd6b7c0ea472cfbc7ece55bc64bc5d85be4a6c0 100644 +--- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java +@@ -73,7 +73,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { + // CraftBukkit start - moved down + // entity.clearFire(); + if (entity.mayInteract(worldserver, pos)) { +- if (this.handleEntityOnFireInside(state, world, pos, entity)) { ++ if (this.handleEntityOnFireInsideWithEvent(state, world, pos, entity)) { // Paper - fix powdered snow cauldron extinguishing entities + entity.clearFire(); + } + // CraftBukkit end +@@ -84,6 +84,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { + } + + // CraftBukkit start ++ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - fix powdered snow cauldron extinguishing entities; use #handleEntityOnFireInsideWithEvent + private boolean handleEntityOnFireInside(BlockState iblockdata, Level world, BlockPos blockposition, Entity entity) { + if (this.precipitationType == Biome.Precipitation.SNOW) { + return LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL)), world, blockposition, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH); +@@ -93,6 +94,15 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { + } + + } ++ // Paper start - fix powdered snow cauldron extinguishing entities ++ protected boolean handleEntityOnFireInsideWithEvent(BlockState state, Level world, BlockPos pos, Entity entity) { ++ if (this.precipitationType == Biome.Precipitation.SNOW) { ++ return LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) state.getValue(LayeredCauldronBlock.LEVEL)), world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH); ++ } else { ++ return LayeredCauldronBlock.lowerFillLevel(state, world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH); ++ } ++ } ++ // Paper end - fix powdered snow cauldron extinguishing entities + + public static void lowerFillLevel(BlockState state, Level world, BlockPos pos) { + // CraftBukkit start diff --git a/patches/server/0693-Add-PlayerStopUsingItemEvent.patch b/patches/server/0693-Add-PlayerStopUsingItemEvent.patch new file mode 100644 index 0000000000..2e1c8f29d0 --- /dev/null +++ b/patches/server/0693-Add-PlayerStopUsingItemEvent.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: u9g +Date: Tue, 3 May 2022 20:41:37 -0400 +Subject: [PATCH] Add PlayerStopUsingItemEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 8b454382f59ee36ec6f45ca8445b3f1a956ff668..786ac2127bc743cf2a33776314a4b5c197f35538 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -4202,6 +4202,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + + public void releaseUsingItem() { + if (!this.useItem.isEmpty()) { ++ if (this instanceof ServerPlayer) new io.papermc.paper.event.player.PlayerStopUsingItemEvent((Player) getBukkitEntity(), useItem.asBukkitMirror(), getTicksUsingItem()).callEvent(); // Paper - Add PlayerStopUsingItemEvent + this.useItem.releaseUsing(this.level(), this, this.getUseItemRemainingTicks()); + if (this.useItem.useOnRelease()) { + this.updatingUsingItem(); diff --git a/patches/server/0693-fix-powder-snow-cauldrons-not-turning-to-water.patch b/patches/server/0693-fix-powder-snow-cauldrons-not-turning-to-water.patch deleted file mode 100644 index 201c323a35..0000000000 --- a/patches/server/0693-fix-powder-snow-cauldrons-not-turning-to-water.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 30 Dec 2021 14:02:13 -0800 -Subject: [PATCH] fix powder snow cauldrons not turning to water - -Powder snow cauldrons should turn to water when -extinguishing an entity - -diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -index 806d18689126d0a971665a33d7fc91102ec76db5..7dd6b7c0ea472cfbc7ece55bc64bc5d85be4a6c0 100644 ---- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -@@ -73,7 +73,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { - // CraftBukkit start - moved down - // entity.clearFire(); - if (entity.mayInteract(worldserver, pos)) { -- if (this.handleEntityOnFireInside(state, world, pos, entity)) { -+ if (this.handleEntityOnFireInsideWithEvent(state, world, pos, entity)) { // Paper - fix powdered snow cauldron extinguishing entities - entity.clearFire(); - } - // CraftBukkit end -@@ -84,6 +84,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { - } - - // CraftBukkit start -+ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - fix powdered snow cauldron extinguishing entities; use #handleEntityOnFireInsideWithEvent - private boolean handleEntityOnFireInside(BlockState iblockdata, Level world, BlockPos blockposition, Entity entity) { - if (this.precipitationType == Biome.Precipitation.SNOW) { - return LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL)), world, blockposition, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH); -@@ -93,6 +94,15 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { - } - - } -+ // Paper start - fix powdered snow cauldron extinguishing entities -+ protected boolean handleEntityOnFireInsideWithEvent(BlockState state, Level world, BlockPos pos, Entity entity) { -+ if (this.precipitationType == Biome.Precipitation.SNOW) { -+ return LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) state.getValue(LayeredCauldronBlock.LEVEL)), world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH); -+ } else { -+ return LayeredCauldronBlock.lowerFillLevel(state, world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH); -+ } -+ } -+ // Paper end - fix powdered snow cauldron extinguishing entities - - public static void lowerFillLevel(BlockState state, Level world, BlockPos pos) { - // CraftBukkit start diff --git a/patches/server/0694-Add-PlayerStopUsingItemEvent.patch b/patches/server/0694-Add-PlayerStopUsingItemEvent.patch deleted file mode 100644 index c7cab9712f..0000000000 --- a/patches/server/0694-Add-PlayerStopUsingItemEvent.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: u9g -Date: Tue, 3 May 2022 20:41:37 -0400 -Subject: [PATCH] Add PlayerStopUsingItemEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 0aa7291b3c28c58767fed5f9f01e381b671b5d27..d41c0f1aa501cbe17c88029bafbe034901f6d562 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4204,6 +4204,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - - public void releaseUsingItem() { - if (!this.useItem.isEmpty()) { -+ if (this instanceof ServerPlayer) new io.papermc.paper.event.player.PlayerStopUsingItemEvent((Player) getBukkitEntity(), useItem.asBukkitMirror(), getTicksUsingItem()).callEvent(); // Paper - Add PlayerStopUsingItemEvent - this.useItem.releaseUsing(this.level(), this, this.getUseItemRemainingTicks()); - if (this.useItem.useOnRelease()) { - this.updatingUsingItem(); diff --git a/patches/server/0694-Don-t-tick-markers.patch b/patches/server/0694-Don-t-tick-markers.patch new file mode 100644 index 0000000000..e5c290a988 --- /dev/null +++ b/patches/server/0694-Don-t-tick-markers.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Fri, 7 Jan 2022 11:58:26 +0100 +Subject: [PATCH] Don't tick markers + +Fixes https://github.com/PaperMC/Paper/issues/7276 and https://github.com/PaperMC/Paper/issues/8118 +by using a config option that, when set to false, does not add markers to the entity +tick list at all and ignores them in Spigot's activation range checks. The entity tick +list is only used in the tick and tickPassenger methods, so we can safely not add the +markers to it. When the config option is set to true, markers are ticked as normal. + +diff --git a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java +index 67fcba634f8183bb33834ac3b2c3dcfb8d87129e..777b789fdcdf297309cfb36fc7f77e3fdb6327ca 100644 +--- a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java ++++ b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java +@@ -109,7 +109,7 @@ public final class EntityCommand implements PaperSubcommand { + ChunkPos chunk = e.chunkPosition(); + info.left++; + info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1); +- if (!chunkProviderServer.isPositionTicking(e)) { ++ if (!chunkProviderServer.isPositionTicking(e) || (e instanceof net.minecraft.world.entity.Marker && !world.paperConfig().entities.markers.tick)) { // Paper - Configurable marker ticking + nonEntityTicking.merge(key, 1, Integer::sum); + } + }); +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 2d77e9526917a83987ae0486a669538d5417b781..f4b1b5f1903015b3c4650186466c8183560c9de0 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2219,6 +2219,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + + public void onTickingStart(Entity entity) { ++ if (entity instanceof net.minecraft.world.entity.Marker && !paperConfig().entities.markers.tick) return; // Paper - Configurable marker ticking + ServerLevel.this.entityTickList.add(entity); + } + diff --git a/patches/server/0695-Don-t-tick-markers.patch b/patches/server/0695-Don-t-tick-markers.patch deleted file mode 100644 index c20ce60044..0000000000 --- a/patches/server/0695-Don-t-tick-markers.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Fri, 7 Jan 2022 11:58:26 +0100 -Subject: [PATCH] Don't tick markers - -Fixes https://github.com/PaperMC/Paper/issues/7276 and https://github.com/PaperMC/Paper/issues/8118 -by using a config option that, when set to false, does not add markers to the entity -tick list at all and ignores them in Spigot's activation range checks. The entity tick -list is only used in the tick and tickPassenger methods, so we can safely not add the -markers to it. When the config option is set to true, markers are ticked as normal. - -diff --git a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -index 67fcba634f8183bb33834ac3b2c3dcfb8d87129e..777b789fdcdf297309cfb36fc7f77e3fdb6327ca 100644 ---- a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -+++ b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -@@ -109,7 +109,7 @@ public final class EntityCommand implements PaperSubcommand { - ChunkPos chunk = e.chunkPosition(); - info.left++; - info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1); -- if (!chunkProviderServer.isPositionTicking(e)) { -+ if (!chunkProviderServer.isPositionTicking(e) || (e instanceof net.minecraft.world.entity.Marker && !world.paperConfig().entities.markers.tick)) { // Paper - Configurable marker ticking - nonEntityTicking.merge(key, 1, Integer::sum); - } - }); -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 9ac6d2e87bbad00c9b97028b0e9c2a42cf29801b..cb33c53d441d2d535b48cb80f5ac445b52cd98be 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2249,6 +2249,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - public void onTickingStart(Entity entity) { -+ if (entity instanceof net.minecraft.world.entity.Marker && !paperConfig().entities.markers.tick) return; // Paper - Configurable marker ticking - ServerLevel.this.entityTickList.add(entity); - } - diff --git a/patches/server/0695-Expand-FallingBlock-API.patch b/patches/server/0695-Expand-FallingBlock-API.patch new file mode 100644 index 0000000000..7992fef972 --- /dev/null +++ b/patches/server/0695-Expand-FallingBlock-API.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 5 Dec 2021 14:58:17 -0500 +Subject: [PATCH] Expand FallingBlock API + +- add auto expire setting +- add setter for block data +- add accessors for block state + +== AT == +public net.minecraft.world.entity.item.FallingBlockEntity blockState + +Co-authored-by: Lukas Planz + +diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +index 72abeb4f37b70094498ed3b18e8f73346ba0ead0..0ecda05a98046938546fe7bc6cf2590c886add41 100644 +--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java ++++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +@@ -71,6 +71,7 @@ public class FallingBlockEntity extends Entity { + public CompoundTag blockData; + public boolean forceTickAfterTeleportToDuplicate; + protected static final EntityDataAccessor DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS); ++ public boolean autoExpire = true; // Paper - Expand FallingBlock API + + public FallingBlockEntity(EntityType type, Level world) { + super(type, world); +@@ -191,7 +192,7 @@ public class FallingBlockEntity extends Entity { + } + + if (!this.onGround() && !flag1) { +- if (this.time > 100 && (blockposition.getY() <= this.level().getMinY() || blockposition.getY() > this.level().getMaxY()) || this.time > 600) { ++ if ((this.time > 100 && autoExpire) && (blockposition.getY() <= this.level().getMinY() || blockposition.getY() > this.level().getMaxY()) || (this.time > 600 && autoExpire)) { // Paper - Expand FallingBlock API + if (this.dropItem && worldserver.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { + this.spawnAtLocation(worldserver, (ItemLike) block); + } +@@ -338,6 +339,7 @@ public class FallingBlockEntity extends Entity { + } + + nbt.putBoolean("CancelDrop", this.cancelDrop); ++ if (!autoExpire) {nbt.putBoolean("Paper.AutoExpire", false);} // Paper - Expand FallingBlock API + } + + @Override +@@ -365,6 +367,11 @@ public class FallingBlockEntity extends Entity { + this.blockState = Blocks.SAND.defaultBlockState(); + } + ++ // Paper start - Expand FallingBlock API ++ if (nbt.contains("Paper.AutoExpire")) { ++ this.autoExpire = nbt.getBoolean("Paper.AutoExpire"); ++ } ++ // Paper end - Expand FallingBlock API + } + + public void setHurtsEntities(float fallHurtAmount, int fallHurtMax) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java +index a7a3f74b846112d752fe04162b30805961457b11..1359d25a32b4a5d5e8e68ce737bd19f7b5afaf69 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java +@@ -33,6 +33,31 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { + public BlockData getBlockData() { + return CraftBlockData.fromData(this.getHandle().getBlockState()); + } ++ // Paper start - Expand FallingBlock API ++ @Override ++ public void setBlockData(final BlockData blockData) { ++ Preconditions.checkArgument(blockData != null, "blockData"); ++ final net.minecraft.world.level.block.state.BlockState oldState = this.getHandle().blockState, newState = ((CraftBlockData) blockData).getState(); ++ this.getHandle().blockState = newState; ++ this.getHandle().blockData = null; ++ ++ if (oldState != newState) this.update(); ++ } ++ ++ @Override ++ public org.bukkit.block.BlockState getBlockState() { ++ return org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.getHandle().blockState, this.getHandle().blockData); ++ } ++ ++ @Override ++ public void setBlockState(final org.bukkit.block.BlockState blockState) { ++ Preconditions.checkArgument(blockState != null, "blockState"); ++ // Calls #update if needed, the block data compound tag is not synced with the client and hence can be mutated after the sync with clients. ++ // The call also clears any potential old block data. ++ this.setBlockData(blockState.getBlockData()); ++ if (blockState instanceof final org.bukkit.craftbukkit.block.CraftBlockEntityState tileEntity) this.getHandle().blockData = tileEntity.getSnapshotNBT(); ++ } ++ // Paper end - Expand FallingBlock API + + @Override + public boolean getDropItem() { +@@ -101,4 +126,15 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { + this.setHurtEntities(true); + } + } ++ // Paper start - Expand FallingBlock API ++ @Override ++ public boolean doesAutoExpire() { ++ return this.getHandle().autoExpire; ++ } ++ ++ @Override ++ public void shouldAutoExpire(boolean autoExpires) { ++ this.getHandle().autoExpire = autoExpires; ++ } ++ // Paper end - Expand FallingBlock API + } diff --git a/patches/server/0696-Add-support-for-Proxy-Protocol.patch b/patches/server/0696-Add-support-for-Proxy-Protocol.patch new file mode 100644 index 0000000000..5d35c10858 --- /dev/null +++ b/patches/server/0696-Add-support-for-Proxy-Protocol.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: PanSzelescik +Date: Thu, 7 Apr 2022 16:13:39 +0200 +Subject: [PATCH] Add support for Proxy Protocol + + +diff --git a/build.gradle.kts b/build.gradle.kts +index 38585b7f0b8e1e287b37820924a1b0d464fe9e99..25001d6cf4f70bd01ab304625b49ec45f5b1f525 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -28,6 +28,7 @@ dependencies { + log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins + runtimeOnly(log4jPlugins.output) + alsoShade(log4jPlugins.output) ++ implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Paper - Add support for proxy protocol + // Paper end + implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") // Paper - remove exclusion + implementation("org.ow2.asm:asm-commons:9.7.1") +diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +index c63c194c44646e6bc1a59426552787011fc2ced5..c62df32af11636ad408b584fcc590590ce4fb0d0 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java ++++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +@@ -104,6 +104,12 @@ public class ServerConnectionListener { + ServerConnectionListener.LOGGER.info("Using default channel type"); + } + ++ // Paper start - Warn people with console access that HAProxy is in use. ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) { ++ ServerConnectionListener.LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled."); ++ } ++ // Paper end - Warn people with console access that HAProxy is in use. ++ + this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer() { + protected void initChannel(Channel channel) { + try { +@@ -123,6 +129,29 @@ public class ServerConnectionListener { + Connection object = j > 0 ? new RateKickingConnection(j) : new Connection(PacketFlow.SERVERBOUND); // CraftBukkit - decompile error + + //ServerConnectionListener.this.connections.add(object); // Paper ++ // Paper start - Add support for Proxy Protocol ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) { ++ channel.pipeline().addAfter("timeout", "haproxy-decoder", new io.netty.handler.codec.haproxy.HAProxyMessageDecoder()); ++ channel.pipeline().addAfter("haproxy-decoder", "haproxy-handler", new ChannelInboundHandlerAdapter() { ++ @Override ++ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ++ if (msg instanceof io.netty.handler.codec.haproxy.HAProxyMessage message) { ++ if (message.command() == io.netty.handler.codec.haproxy.HAProxyCommand.PROXY) { ++ String realaddress = message.sourceAddress(); ++ int realport = message.sourcePort(); ++ ++ SocketAddress socketaddr = new java.net.InetSocketAddress(realaddress, realport); ++ ++ Connection connection = (Connection) channel.pipeline().get("packet_handler"); ++ connection.address = socketaddr; ++ } ++ } else { ++ super.channelRead(ctx, msg); ++ } ++ } ++ }); ++ } ++ // Paper end - Add support for proxy protocol + pending.add(object); // Paper - prevent blocking on adding a new connection while the server is ticking + ((Connection) object).configurePacketHandler(channelpipeline); + ((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); diff --git a/patches/server/0696-Expand-FallingBlock-API.patch b/patches/server/0696-Expand-FallingBlock-API.patch deleted file mode 100644 index 7992fef972..0000000000 --- a/patches/server/0696-Expand-FallingBlock-API.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 5 Dec 2021 14:58:17 -0500 -Subject: [PATCH] Expand FallingBlock API - -- add auto expire setting -- add setter for block data -- add accessors for block state - -== AT == -public net.minecraft.world.entity.item.FallingBlockEntity blockState - -Co-authored-by: Lukas Planz - -diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 72abeb4f37b70094498ed3b18e8f73346ba0ead0..0ecda05a98046938546fe7bc6cf2590c886add41 100644 ---- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -71,6 +71,7 @@ public class FallingBlockEntity extends Entity { - public CompoundTag blockData; - public boolean forceTickAfterTeleportToDuplicate; - protected static final EntityDataAccessor DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS); -+ public boolean autoExpire = true; // Paper - Expand FallingBlock API - - public FallingBlockEntity(EntityType type, Level world) { - super(type, world); -@@ -191,7 +192,7 @@ public class FallingBlockEntity extends Entity { - } - - if (!this.onGround() && !flag1) { -- if (this.time > 100 && (blockposition.getY() <= this.level().getMinY() || blockposition.getY() > this.level().getMaxY()) || this.time > 600) { -+ if ((this.time > 100 && autoExpire) && (blockposition.getY() <= this.level().getMinY() || blockposition.getY() > this.level().getMaxY()) || (this.time > 600 && autoExpire)) { // Paper - Expand FallingBlock API - if (this.dropItem && worldserver.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { - this.spawnAtLocation(worldserver, (ItemLike) block); - } -@@ -338,6 +339,7 @@ public class FallingBlockEntity extends Entity { - } - - nbt.putBoolean("CancelDrop", this.cancelDrop); -+ if (!autoExpire) {nbt.putBoolean("Paper.AutoExpire", false);} // Paper - Expand FallingBlock API - } - - @Override -@@ -365,6 +367,11 @@ public class FallingBlockEntity extends Entity { - this.blockState = Blocks.SAND.defaultBlockState(); - } - -+ // Paper start - Expand FallingBlock API -+ if (nbt.contains("Paper.AutoExpire")) { -+ this.autoExpire = nbt.getBoolean("Paper.AutoExpire"); -+ } -+ // Paper end - Expand FallingBlock API - } - - public void setHurtsEntities(float fallHurtAmount, int fallHurtMax) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java -index a7a3f74b846112d752fe04162b30805961457b11..1359d25a32b4a5d5e8e68ce737bd19f7b5afaf69 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java -@@ -33,6 +33,31 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { - public BlockData getBlockData() { - return CraftBlockData.fromData(this.getHandle().getBlockState()); - } -+ // Paper start - Expand FallingBlock API -+ @Override -+ public void setBlockData(final BlockData blockData) { -+ Preconditions.checkArgument(blockData != null, "blockData"); -+ final net.minecraft.world.level.block.state.BlockState oldState = this.getHandle().blockState, newState = ((CraftBlockData) blockData).getState(); -+ this.getHandle().blockState = newState; -+ this.getHandle().blockData = null; -+ -+ if (oldState != newState) this.update(); -+ } -+ -+ @Override -+ public org.bukkit.block.BlockState getBlockState() { -+ return org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.getHandle().blockState, this.getHandle().blockData); -+ } -+ -+ @Override -+ public void setBlockState(final org.bukkit.block.BlockState blockState) { -+ Preconditions.checkArgument(blockState != null, "blockState"); -+ // Calls #update if needed, the block data compound tag is not synced with the client and hence can be mutated after the sync with clients. -+ // The call also clears any potential old block data. -+ this.setBlockData(blockState.getBlockData()); -+ if (blockState instanceof final org.bukkit.craftbukkit.block.CraftBlockEntityState tileEntity) this.getHandle().blockData = tileEntity.getSnapshotNBT(); -+ } -+ // Paper end - Expand FallingBlock API - - @Override - public boolean getDropItem() { -@@ -101,4 +126,15 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { - this.setHurtEntities(true); - } - } -+ // Paper start - Expand FallingBlock API -+ @Override -+ public boolean doesAutoExpire() { -+ return this.getHandle().autoExpire; -+ } -+ -+ @Override -+ public void shouldAutoExpire(boolean autoExpires) { -+ this.getHandle().autoExpire = autoExpires; -+ } -+ // Paper end - Expand FallingBlock API - } diff --git a/patches/server/0697-Add-support-for-Proxy-Protocol.patch b/patches/server/0697-Add-support-for-Proxy-Protocol.patch deleted file mode 100644 index 5d35c10858..0000000000 --- a/patches/server/0697-Add-support-for-Proxy-Protocol.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: PanSzelescik -Date: Thu, 7 Apr 2022 16:13:39 +0200 -Subject: [PATCH] Add support for Proxy Protocol - - -diff --git a/build.gradle.kts b/build.gradle.kts -index 38585b7f0b8e1e287b37820924a1b0d464fe9e99..25001d6cf4f70bd01ab304625b49ec45f5b1f525 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -28,6 +28,7 @@ dependencies { - log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins - runtimeOnly(log4jPlugins.output) - alsoShade(log4jPlugins.output) -+ implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Paper - Add support for proxy protocol - // Paper end - implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") // Paper - remove exclusion - implementation("org.ow2.asm:asm-commons:9.7.1") -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index c63c194c44646e6bc1a59426552787011fc2ced5..c62df32af11636ad408b584fcc590590ce4fb0d0 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -104,6 +104,12 @@ public class ServerConnectionListener { - ServerConnectionListener.LOGGER.info("Using default channel type"); - } - -+ // Paper start - Warn people with console access that HAProxy is in use. -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) { -+ ServerConnectionListener.LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled."); -+ } -+ // Paper end - Warn people with console access that HAProxy is in use. -+ - this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer() { - protected void initChannel(Channel channel) { - try { -@@ -123,6 +129,29 @@ public class ServerConnectionListener { - Connection object = j > 0 ? new RateKickingConnection(j) : new Connection(PacketFlow.SERVERBOUND); // CraftBukkit - decompile error - - //ServerConnectionListener.this.connections.add(object); // Paper -+ // Paper start - Add support for Proxy Protocol -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) { -+ channel.pipeline().addAfter("timeout", "haproxy-decoder", new io.netty.handler.codec.haproxy.HAProxyMessageDecoder()); -+ channel.pipeline().addAfter("haproxy-decoder", "haproxy-handler", new ChannelInboundHandlerAdapter() { -+ @Override -+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { -+ if (msg instanceof io.netty.handler.codec.haproxy.HAProxyMessage message) { -+ if (message.command() == io.netty.handler.codec.haproxy.HAProxyCommand.PROXY) { -+ String realaddress = message.sourceAddress(); -+ int realport = message.sourcePort(); -+ -+ SocketAddress socketaddr = new java.net.InetSocketAddress(realaddress, realport); -+ -+ Connection connection = (Connection) channel.pipeline().get("packet_handler"); -+ connection.address = socketaddr; -+ } -+ } else { -+ super.channelRead(ctx, msg); -+ } -+ } -+ }); -+ } -+ // Paper end - Add support for proxy protocol - pending.add(object); // Paper - prevent blocking on adding a new connection while the server is ticking - ((Connection) object).configurePacketHandler(channelpipeline); - ((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); diff --git a/patches/server/0697-Fix-OfflinePlayer-getBedSpawnLocation.patch b/patches/server/0697-Fix-OfflinePlayer-getBedSpawnLocation.patch new file mode 100644 index 0000000000..4726c2f65c --- /dev/null +++ b/patches/server/0697-Fix-OfflinePlayer-getBedSpawnLocation.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 30 May 2022 16:03:36 -0700 +Subject: [PATCH] Fix OfflinePlayer#getBedSpawnLocation + +When calling getBedSpawnLocation on an +instance of CraftOfflinePlayer the world was incorrect +due to the logic for reading the NBT not being up-to-date. + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +index e0d342a0ddd140b342f7af138c71596c6d718788..30c1c203022c2ed777dcddfd68ef2e3752c62ea1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +@@ -37,6 +37,7 @@ import org.bukkit.profile.PlayerProfile; + + @SerializableAs("Player") + public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializable { ++ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper + private final GameProfile profile; + private final CraftServer server; + private final PlayerDataStorage storage; +@@ -361,11 +362,20 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa + if (data == null) return null; + + if (data.contains("SpawnX") && data.contains("SpawnY") && data.contains("SpawnZ")) { +- String spawnWorld = data.getString("SpawnWorld"); +- if (spawnWorld.equals("")) { +- spawnWorld = this.server.getWorlds().get(0).getName(); ++ // Paper start - fix wrong world ++ final float respawnAngle = data.getFloat("SpawnAngle"); ++ org.bukkit.World spawnWorld = this.server.getWorld(data.getString("SpawnWorld")); // legacy ++ if (data.contains("SpawnDimension")) { ++ com.mojang.serialization.DataResult> result = net.minecraft.world.level.Level.RESOURCE_KEY_CODEC.parse(net.minecraft.nbt.NbtOps.INSTANCE, data.get("SpawnDimension")); ++ net.minecraft.resources.ResourceKey levelKey = result.resultOrPartial(LOGGER::error).orElse(net.minecraft.world.level.Level.OVERWORLD); ++ net.minecraft.server.level.ServerLevel level = this.server.console.getLevel(levelKey); ++ spawnWorld = level != null ? level.getWorld() : spawnWorld; + } +- return new Location(this.server.getWorld(spawnWorld), data.getInt("SpawnX"), data.getInt("SpawnY"), data.getInt("SpawnZ")); ++ if (spawnWorld == null) { ++ return null; ++ } ++ return new Location(spawnWorld, data.getInt("SpawnX"), data.getInt("SpawnY"), data.getInt("SpawnZ"), respawnAngle, 0); ++ // Paper end + } + return null; + } diff --git a/patches/server/0698-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch b/patches/server/0698-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch new file mode 100644 index 0000000000..7158b83635 --- /dev/null +++ b/patches/server/0698-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 1 Jan 2022 23:11:26 -0800 +Subject: [PATCH] Fix FurnaceInventory for smokers and blast furnaces + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java +index a6c758c5c5da2fb3f2d251bc109f72a5d8b0eb14..ad2cb9a1352abd855bf11a390c9788835857380a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java +@@ -65,7 +65,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + return new CraftInventory(tileEntity); + } + +- public static class Furnace extends CraftTileInventoryConverter { ++ public static class Furnace extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical + + @Override + public Container getTileEntity() { +@@ -73,6 +73,11 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + return furnace; + } + ++ // Paper start - abstract furnace converter to apply to all 3 furnaces ++ } ++ ++ public static abstract class AbstractFurnaceInventoryConverter extends CraftTileInventoryConverter { ++ // Paper end - abstract furnace converter to apply to all 3 furnaces + // Paper start + @Override + public Inventory createInventory(InventoryHolder owner, InventoryType type, net.kyori.adventure.text.Component title) { +@@ -170,7 +175,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + } + } + +- public static class BlastFurnace extends CraftTileInventoryConverter { ++ public static class BlastFurnace extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical + + @Override + public Container getTileEntity() { +@@ -186,7 +191,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + } + } + +- public static class Smoker extends CraftTileInventoryConverter { ++ public static class Smoker extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical + + @Override + public Container getTileEntity() { diff --git a/patches/server/0698-Fix-OfflinePlayer-getBedSpawnLocation.patch b/patches/server/0698-Fix-OfflinePlayer-getBedSpawnLocation.patch deleted file mode 100644 index 4726c2f65c..0000000000 --- a/patches/server/0698-Fix-OfflinePlayer-getBedSpawnLocation.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 30 May 2022 16:03:36 -0700 -Subject: [PATCH] Fix OfflinePlayer#getBedSpawnLocation - -When calling getBedSpawnLocation on an -instance of CraftOfflinePlayer the world was incorrect -due to the logic for reading the NBT not being up-to-date. - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -index e0d342a0ddd140b342f7af138c71596c6d718788..30c1c203022c2ed777dcddfd68ef2e3752c62ea1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -@@ -37,6 +37,7 @@ import org.bukkit.profile.PlayerProfile; - - @SerializableAs("Player") - public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializable { -+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper - private final GameProfile profile; - private final CraftServer server; - private final PlayerDataStorage storage; -@@ -361,11 +362,20 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa - if (data == null) return null; - - if (data.contains("SpawnX") && data.contains("SpawnY") && data.contains("SpawnZ")) { -- String spawnWorld = data.getString("SpawnWorld"); -- if (spawnWorld.equals("")) { -- spawnWorld = this.server.getWorlds().get(0).getName(); -+ // Paper start - fix wrong world -+ final float respawnAngle = data.getFloat("SpawnAngle"); -+ org.bukkit.World spawnWorld = this.server.getWorld(data.getString("SpawnWorld")); // legacy -+ if (data.contains("SpawnDimension")) { -+ com.mojang.serialization.DataResult> result = net.minecraft.world.level.Level.RESOURCE_KEY_CODEC.parse(net.minecraft.nbt.NbtOps.INSTANCE, data.get("SpawnDimension")); -+ net.minecraft.resources.ResourceKey levelKey = result.resultOrPartial(LOGGER::error).orElse(net.minecraft.world.level.Level.OVERWORLD); -+ net.minecraft.server.level.ServerLevel level = this.server.console.getLevel(levelKey); -+ spawnWorld = level != null ? level.getWorld() : spawnWorld; - } -- return new Location(this.server.getWorld(spawnWorld), data.getInt("SpawnX"), data.getInt("SpawnY"), data.getInt("SpawnZ")); -+ if (spawnWorld == null) { -+ return null; -+ } -+ return new Location(spawnWorld, data.getInt("SpawnX"), data.getInt("SpawnY"), data.getInt("SpawnZ"), respawnAngle, 0); -+ // Paper end - } - return null; - } diff --git a/patches/server/0699-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch b/patches/server/0699-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch deleted file mode 100644 index 7158b83635..0000000000 --- a/patches/server/0699-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 1 Jan 2022 23:11:26 -0800 -Subject: [PATCH] Fix FurnaceInventory for smokers and blast furnaces - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java -index a6c758c5c5da2fb3f2d251bc109f72a5d8b0eb14..ad2cb9a1352abd855bf11a390c9788835857380a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java -@@ -65,7 +65,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat - return new CraftInventory(tileEntity); - } - -- public static class Furnace extends CraftTileInventoryConverter { -+ public static class Furnace extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical - - @Override - public Container getTileEntity() { -@@ -73,6 +73,11 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat - return furnace; - } - -+ // Paper start - abstract furnace converter to apply to all 3 furnaces -+ } -+ -+ public static abstract class AbstractFurnaceInventoryConverter extends CraftTileInventoryConverter { -+ // Paper end - abstract furnace converter to apply to all 3 furnaces - // Paper start - @Override - public Inventory createInventory(InventoryHolder owner, InventoryType type, net.kyori.adventure.text.Component title) { -@@ -170,7 +175,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat - } - } - -- public static class BlastFurnace extends CraftTileInventoryConverter { -+ public static class BlastFurnace extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical - - @Override - public Container getTileEntity() { -@@ -186,7 +191,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat - } - } - -- public static class Smoker extends CraftTileInventoryConverter { -+ public static class Smoker extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical - - @Override - public Container getTileEntity() { diff --git a/patches/server/0699-Sanitize-sent-BlockEntity-NBT.patch b/patches/server/0699-Sanitize-sent-BlockEntity-NBT.patch new file mode 100644 index 0000000000..60a49fa4ef --- /dev/null +++ b/patches/server/0699-Sanitize-sent-BlockEntity-NBT.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Fri, 3 Dec 2021 16:55:50 -0500 +Subject: [PATCH] Sanitize sent BlockEntity NBT + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java +index 4f3ba61f13dbe5773034a19e749b7c4f5dc3d291..5d3e739d28d394ed59fe0003245cc55ac62e6087 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java +@@ -29,7 +29,7 @@ public class ClientboundBlockEntityDataPacket implements Packet nbtGetter) { + RegistryAccess registryAccess = blockEntity.getLevel().registryAccess(); +- return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), nbtGetter.apply(blockEntity, registryAccess)); ++ return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), blockEntity.sanitizeSentNbt(nbtGetter.apply(blockEntity, registryAccess))); // Paper - Sanitize sent data + } + + public static ClientboundBlockEntityDataPacket create(BlockEntity blockEntity) { +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +index ac900dfdc5c90e9e60d47efa734be8f0a5b20dca..ec1cb034d840633240f2b379b09f7d2f1c8971a5 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +@@ -154,6 +154,7 @@ public class ClientboundLevelChunkPacketData { + CompoundTag compoundTag = blockEntity.getUpdateTag(blockEntity.getLevel().registryAccess()); + BlockPos blockPos = blockEntity.getBlockPos(); + int i = SectionPos.sectionRelative(blockPos.getX()) << 4 | SectionPos.sectionRelative(blockPos.getZ()); ++ blockEntity.sanitizeSentNbt(compoundTag); // Paper - Sanitize sent data + return new ClientboundLevelChunkPacketData.BlockEntityInfo(i, blockPos.getY(), blockEntity.getType(), compoundTag.isEmpty() ? null : compoundTag); + } + } +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +index 09b85c4caa4ebaae1e8c2910b090c40a039a1be7..645a7ec0709cbd3c0cfbf75f7b8622a67515f74c 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -390,6 +390,14 @@ public abstract class BlockEntity { + } + // CraftBukkit end + ++ // Paper start - Sanitize sent data ++ public CompoundTag sanitizeSentNbt(CompoundTag tag) { ++ tag.remove("PublicBukkitValues"); ++ ++ return tag; ++ } ++ // Paper end - Sanitize sent data ++ + private static class ComponentHelper { + + public static final Codec COMPONENTS_CODEC = DataComponentMap.CODEC.optionalFieldOf("components", DataComponentMap.EMPTY).codec(); diff --git a/patches/server/0700-Disable-component-selector-resolving-in-books-by-def.patch b/patches/server/0700-Disable-component-selector-resolving-in-books-by-def.patch new file mode 100644 index 0000000000..7231198032 --- /dev/null +++ b/patches/server/0700-Disable-component-selector-resolving-in-books-by-def.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 2 Jun 2022 20:35:58 +0200 +Subject: [PATCH] Disable component selector resolving in books by default + + +diff --git a/src/main/java/net/minecraft/world/item/WrittenBookItem.java b/src/main/java/net/minecraft/world/item/WrittenBookItem.java +index a282c1cbbdf8e5ebac547b45a58116f9b4b2d49e..0c54100fb72b79e0eb4bad8f6851648e084d9260 100644 +--- a/src/main/java/net/minecraft/world/item/WrittenBookItem.java ++++ b/src/main/java/net/minecraft/world/item/WrittenBookItem.java +@@ -41,7 +41,7 @@ public class WrittenBookItem extends Item { + + public static boolean resolveBookComponents(ItemStack book, CommandSourceStack commandSource, @Nullable Player player) { + WrittenBookContent writtenBookContent = book.get(DataComponents.WRITTEN_BOOK_CONTENT); +- if (writtenBookContent != null && !writtenBookContent.resolved()) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && writtenBookContent != null && !writtenBookContent.resolved()) { // Paper - Disable component selector resolving in books by default + WrittenBookContent writtenBookContent2 = writtenBookContent.resolve(commandSource, player); + if (writtenBookContent2 != null) { + book.set(DataComponents.WRITTEN_BOOK_CONTENT, writtenBookContent2); diff --git a/patches/server/0700-Sanitize-sent-BlockEntity-NBT.patch b/patches/server/0700-Sanitize-sent-BlockEntity-NBT.patch deleted file mode 100644 index e9d1e188af..0000000000 --- a/patches/server/0700-Sanitize-sent-BlockEntity-NBT.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Fri, 3 Dec 2021 16:55:50 -0500 -Subject: [PATCH] Sanitize sent BlockEntity NBT - - -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java -index 4f3ba61f13dbe5773034a19e749b7c4f5dc3d291..5d3e739d28d394ed59fe0003245cc55ac62e6087 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java -@@ -29,7 +29,7 @@ public class ClientboundBlockEntityDataPacket implements Packet nbtGetter) { - RegistryAccess registryAccess = blockEntity.getLevel().registryAccess(); -- return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), nbtGetter.apply(blockEntity, registryAccess)); -+ return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), blockEntity.sanitizeSentNbt(nbtGetter.apply(blockEntity, registryAccess))); // Paper - Sanitize sent data - } - - public static ClientboundBlockEntityDataPacket create(BlockEntity blockEntity) { -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java -index ac900dfdc5c90e9e60d47efa734be8f0a5b20dca..ec1cb034d840633240f2b379b09f7d2f1c8971a5 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java -@@ -154,6 +154,7 @@ public class ClientboundLevelChunkPacketData { - CompoundTag compoundTag = blockEntity.getUpdateTag(blockEntity.getLevel().registryAccess()); - BlockPos blockPos = blockEntity.getBlockPos(); - int i = SectionPos.sectionRelative(blockPos.getX()) << 4 | SectionPos.sectionRelative(blockPos.getZ()); -+ blockEntity.sanitizeSentNbt(compoundTag); // Paper - Sanitize sent data - return new ClientboundLevelChunkPacketData.BlockEntityInfo(i, blockPos.getY(), blockEntity.getType(), compoundTag.isEmpty() ? null : compoundTag); - } - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 3de01d92e1c97e287a1f0d1f8de81b4f530b4a84..63e234fb72952dcede4eeaa5d3d3390d137d88a2 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -395,6 +395,14 @@ public abstract class BlockEntity { - } - // CraftBukkit end - -+ // Paper start - Sanitize sent data -+ public CompoundTag sanitizeSentNbt(CompoundTag tag) { -+ tag.remove("PublicBukkitValues"); -+ -+ return tag; -+ } -+ // Paper end - Sanitize sent data -+ - private static class ComponentHelper { - - public static final Codec COMPONENTS_CODEC = DataComponentMap.CODEC.optionalFieldOf("components", DataComponentMap.EMPTY).codec(); diff --git a/patches/server/0701-Disable-component-selector-resolving-in-books-by-def.patch b/patches/server/0701-Disable-component-selector-resolving-in-books-by-def.patch deleted file mode 100644 index 7231198032..0000000000 --- a/patches/server/0701-Disable-component-selector-resolving-in-books-by-def.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Thu, 2 Jun 2022 20:35:58 +0200 -Subject: [PATCH] Disable component selector resolving in books by default - - -diff --git a/src/main/java/net/minecraft/world/item/WrittenBookItem.java b/src/main/java/net/minecraft/world/item/WrittenBookItem.java -index a282c1cbbdf8e5ebac547b45a58116f9b4b2d49e..0c54100fb72b79e0eb4bad8f6851648e084d9260 100644 ---- a/src/main/java/net/minecraft/world/item/WrittenBookItem.java -+++ b/src/main/java/net/minecraft/world/item/WrittenBookItem.java -@@ -41,7 +41,7 @@ public class WrittenBookItem extends Item { - - public static boolean resolveBookComponents(ItemStack book, CommandSourceStack commandSource, @Nullable Player player) { - WrittenBookContent writtenBookContent = book.get(DataComponents.WRITTEN_BOOK_CONTENT); -- if (writtenBookContent != null && !writtenBookContent.resolved()) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && writtenBookContent != null && !writtenBookContent.resolved()) { // Paper - Disable component selector resolving in books by default - WrittenBookContent writtenBookContent2 = writtenBookContent.resolve(commandSource, player); - if (writtenBookContent2 != null) { - book.set(DataComponents.WRITTEN_BOOK_CONTENT, writtenBookContent2); diff --git a/patches/server/0701-Prevent-entity-loading-causing-async-lookups.patch b/patches/server/0701-Prevent-entity-loading-causing-async-lookups.patch new file mode 100644 index 0000000000..97d528c05a --- /dev/null +++ b/patches/server/0701-Prevent-entity-loading-causing-async-lookups.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 6 Mar 2022 11:09:09 -0500 +Subject: [PATCH] Prevent entity loading causing async lookups + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index a4a07dc11edf3738698deed929cc224ff7114684..73428cefa737e430c3c8c0d59e1fa763114b8c5a 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -724,6 +724,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("entityBaseTick"); ++ if (firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(level); // Paper - Prevent entity loading causing async lookups + this.inBlockState = null; + if (this.isPassenger() && this.getVehicle().isRemoved()) { + this.stopRiding(); +diff --git a/src/main/java/net/minecraft/world/entity/NeutralMob.java b/src/main/java/net/minecraft/world/entity/NeutralMob.java +index bf577b06707ff197f13f0b5e16620c09d4a69fa8..053d947c4cc00096dae422df36fb8351b3266215 100644 +--- a/src/main/java/net/minecraft/world/entity/NeutralMob.java ++++ b/src/main/java/net/minecraft/world/entity/NeutralMob.java +@@ -45,24 +45,11 @@ public interface NeutralMob { + UUID uuid = nbt.getUUID("AngryAt"); + + this.setPersistentAngerTarget(uuid); +- Entity entity = ((ServerLevel) world).getEntity(uuid); +- +- if (entity != null) { +- if (entity instanceof Mob) { +- Mob entityinsentient = (Mob) entity; +- +- this.setTarget(entityinsentient, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit +- this.setLastHurtByMob(entityinsentient); +- } +- +- if (entity instanceof Player) { +- Player entityhuman = (Player) entity; +- +- this.setTarget(entityhuman, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit +- this.setLastHurtByPlayer(entityhuman); +- } +- +- } ++ // Paper - Prevent entity loading causing async lookups; Moved diff to separate method ++ // If this entity already survived its first tick, e.g. is loaded and ticked in sync, actively ++ // tick the initial persistent anger. ++ // If not, let the first tick on the baseTick call the method later down the line. ++ if (this instanceof Entity entity && !entity.firstTick) this.tickInitialPersistentAnger(world); + } + } + } +@@ -136,4 +123,28 @@ public interface NeutralMob { + + @Nullable + LivingEntity getTarget(); ++ ++ // Paper start - Prevent entity loading causing async lookups ++ // Update last hurt when ticking ++ default void tickInitialPersistentAnger(Level level) { ++ UUID target = getPersistentAngerTarget(); ++ if (target == null) { ++ return; ++ } ++ ++ Entity entity = ((ServerLevel) level).getEntity(target); ++ ++ if (entity != null) { ++ if (entity instanceof Mob mob) { ++ this.setTarget(mob, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit ++ this.setLastHurtByMob(mob); ++ } ++ ++ if (entity instanceof Player player) { ++ this.setTarget(player, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit ++ this.setLastHurtByPlayer(player); ++ } ++ } ++ } ++ // Paper end - Prevent entity loading causing async lookups + } diff --git a/patches/server/0702-Prevent-entity-loading-causing-async-lookups.patch b/patches/server/0702-Prevent-entity-loading-causing-async-lookups.patch deleted file mode 100644 index 97d528c05a..0000000000 --- a/patches/server/0702-Prevent-entity-loading-causing-async-lookups.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 6 Mar 2022 11:09:09 -0500 -Subject: [PATCH] Prevent entity loading causing async lookups - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index a4a07dc11edf3738698deed929cc224ff7114684..73428cefa737e430c3c8c0d59e1fa763114b8c5a 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -724,6 +724,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push("entityBaseTick"); -+ if (firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(level); // Paper - Prevent entity loading causing async lookups - this.inBlockState = null; - if (this.isPassenger() && this.getVehicle().isRemoved()) { - this.stopRiding(); -diff --git a/src/main/java/net/minecraft/world/entity/NeutralMob.java b/src/main/java/net/minecraft/world/entity/NeutralMob.java -index bf577b06707ff197f13f0b5e16620c09d4a69fa8..053d947c4cc00096dae422df36fb8351b3266215 100644 ---- a/src/main/java/net/minecraft/world/entity/NeutralMob.java -+++ b/src/main/java/net/minecraft/world/entity/NeutralMob.java -@@ -45,24 +45,11 @@ public interface NeutralMob { - UUID uuid = nbt.getUUID("AngryAt"); - - this.setPersistentAngerTarget(uuid); -- Entity entity = ((ServerLevel) world).getEntity(uuid); -- -- if (entity != null) { -- if (entity instanceof Mob) { -- Mob entityinsentient = (Mob) entity; -- -- this.setTarget(entityinsentient, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit -- this.setLastHurtByMob(entityinsentient); -- } -- -- if (entity instanceof Player) { -- Player entityhuman = (Player) entity; -- -- this.setTarget(entityhuman, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit -- this.setLastHurtByPlayer(entityhuman); -- } -- -- } -+ // Paper - Prevent entity loading causing async lookups; Moved diff to separate method -+ // If this entity already survived its first tick, e.g. is loaded and ticked in sync, actively -+ // tick the initial persistent anger. -+ // If not, let the first tick on the baseTick call the method later down the line. -+ if (this instanceof Entity entity && !entity.firstTick) this.tickInitialPersistentAnger(world); - } - } - } -@@ -136,4 +123,28 @@ public interface NeutralMob { - - @Nullable - LivingEntity getTarget(); -+ -+ // Paper start - Prevent entity loading causing async lookups -+ // Update last hurt when ticking -+ default void tickInitialPersistentAnger(Level level) { -+ UUID target = getPersistentAngerTarget(); -+ if (target == null) { -+ return; -+ } -+ -+ Entity entity = ((ServerLevel) level).getEntity(target); -+ -+ if (entity != null) { -+ if (entity instanceof Mob mob) { -+ this.setTarget(mob, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit -+ this.setLastHurtByMob(mob); -+ } -+ -+ if (entity instanceof Player player) { -+ this.setTarget(player, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit -+ this.setLastHurtByPlayer(player); -+ } -+ } -+ } -+ // Paper end - Prevent entity loading causing async lookups - } diff --git a/patches/server/0702-Throw-exception-on-world-create-while-being-ticked.patch b/patches/server/0702-Throw-exception-on-world-create-while-being-ticked.patch new file mode 100644 index 0000000000..75ec8c003c --- /dev/null +++ b/patches/server/0702-Throw-exception-on-world-create-while-being-ticked.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 22 Mar 2022 12:44:30 -0700 +Subject: [PATCH] Throw exception on world create while being ticked + +There are no plans to support creating worlds while worlds are +being ticked themselvess. + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index a836ea518bc6d8ddd7c6484038d3d712b3fb13cf..aa9a4a0f35d0200777bdc83520ba82a970bfa900 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -327,6 +327,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { + AtomicReference atomicreference = new AtomicReference(); +@@ -1627,7 +1628,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent +@@ -1687,6 +1690,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop(this.worlds.values()); + } + ++ @Override ++ public boolean isTickingWorlds() { ++ return console.isIteratingOverLevels; ++ } ++ + public DedicatedPlayerList getHandle() { + return this.playerList; + } +@@ -1182,6 +1187,7 @@ public final class CraftServer implements Server { + @Override + public World createWorld(WorldCreator creator) { + Preconditions.checkState(this.console.getAllLevels().iterator().hasNext(), "Cannot create additional worlds on STARTUP"); ++ //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot create a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes. + Preconditions.checkArgument(creator != null, "WorldCreator cannot be null"); + + String name = creator.name(); +@@ -1358,6 +1364,7 @@ public final class CraftServer implements Server { + + @Override + public boolean unloadWorld(World world, boolean save) { ++ //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot unload a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes. + if (world == null) { + return false; + } diff --git a/patches/server/0703-Dont-resent-entity-on-art-update.patch b/patches/server/0703-Dont-resent-entity-on-art-update.patch new file mode 100644 index 0000000000..38d1a4ca58 --- /dev/null +++ b/patches/server/0703-Dont-resent-entity-on-art-update.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 8 Jun 2022 11:04:47 -0400 +Subject: [PATCH] Dont resent entity on art update + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java +index dd02cec9a82794a6b001c3b64f031f78d5fbb812..bcac1359c667ef1ee46384f9c7a5adf4010d2b08 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java +@@ -36,7 +36,7 @@ public class CraftPainting extends CraftHanging implements Painting { + painting.setDirection(painting.getDirection()); + return false; + } +- this.update(); ++ //this.update(); Paper - Don't resent entity on art update + return true; + } + diff --git a/patches/server/0703-Throw-exception-on-world-create-while-being-ticked.patch b/patches/server/0703-Throw-exception-on-world-create-while-being-ticked.patch deleted file mode 100644 index 8b66f840f1..0000000000 --- a/patches/server/0703-Throw-exception-on-world-create-while-being-ticked.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 22 Mar 2022 12:44:30 -0700 -Subject: [PATCH] Throw exception on world create while being ticked - -There are no plans to support creating worlds while worlds are -being ticked themselvess. - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3b0f7e7a5bea786f1189d6e47d8dfd7107d66a53..8fe1514bdc6b2e81a10e445952bd71afa5892552 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -328,6 +328,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { - AtomicReference atomicreference = new AtomicReference(); -@@ -1659,7 +1660,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent -@@ -1725,6 +1728,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop(this.worlds.values()); - } - -+ @Override -+ public boolean isTickingWorlds() { -+ return console.isIteratingOverLevels; -+ } -+ - public DedicatedPlayerList getHandle() { - return this.playerList; - } -@@ -1183,6 +1188,7 @@ public final class CraftServer implements Server { - @Override - public World createWorld(WorldCreator creator) { - Preconditions.checkState(this.console.getAllLevels().iterator().hasNext(), "Cannot create additional worlds on STARTUP"); -+ //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot create a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes. - Preconditions.checkArgument(creator != null, "WorldCreator cannot be null"); - - String name = creator.name(); -@@ -1359,6 +1365,7 @@ public final class CraftServer implements Server { - - @Override - public boolean unloadWorld(World world, boolean save) { -+ //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot unload a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes. - if (world == null) { - return false; - } diff --git a/patches/server/0704-Add-WardenAngerChangeEvent.patch b/patches/server/0704-Add-WardenAngerChangeEvent.patch new file mode 100644 index 0000000000..ca2817ab51 --- /dev/null +++ b/patches/server/0704-Add-WardenAngerChangeEvent.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nopjar +Date: Sun, 12 Jun 2022 02:26:04 +0200 +Subject: [PATCH] Add WardenAngerChangeEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java b/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java +index 27e52ee93ab591e97f37705de64cb5b62c06e253..3d792957f27fd4bdfad8d76262a8e2a2012bf35f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java ++++ b/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java +@@ -146,7 +146,7 @@ public class AngerManagement { + + public int increaseAnger(Entity entity, int amount) { + boolean bl = !this.angerBySuspect.containsKey(entity); +- int i = this.angerBySuspect.computeInt(entity, (suspect, anger) -> Math.min(150, (anger == null ? 0 : anger) + amount)); ++ int i = this.angerBySuspect.computeInt(entity, (suspect, anger) -> Math.min(150, (anger == null ? 0 : anger) + amount)); // Paper - diff on change (Warden#increaseAngerAt WardenAngerChangeEvent) + if (bl) { + int j = this.angerByUuid.removeInt(entity.getUUID()); + i += j; +diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +index 71311d30459d495c57e6fcf0115e4f34a232f1ad..6180019da58b19d2595da508aed3196af922d587 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java ++++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +@@ -482,6 +482,15 @@ public class Warden extends Monster implements VibrationSystem { + @VisibleForTesting + public void increaseAngerAt(@Nullable Entity entity, int amount, boolean listening) { + if (!this.isNoAi() && this.canTargetEntity(entity)) { ++ // Paper start - Add WardenAngerChangeEvent ++ int activeAnger = this.angerManagement.getActiveAnger(entity); ++ io.papermc.paper.event.entity.WardenAngerChangeEvent event = new io.papermc.paper.event.entity.WardenAngerChangeEvent((org.bukkit.entity.Warden) this.getBukkitEntity(), entity.getBukkitEntity(), activeAnger, Math.min(150, activeAnger + amount)); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return; ++ } ++ amount = event.getNewAnger() - activeAnger; ++ // Paper end - Add WardenAngerChangeEvent + WardenAi.setDigCooldown(this); + boolean flag1 = !(this.getTarget() instanceof Player); + int j = this.angerManagement.increaseAnger(entity, amount); diff --git a/patches/server/0704-Dont-resent-entity-on-art-update.patch b/patches/server/0704-Dont-resent-entity-on-art-update.patch deleted file mode 100644 index 38d1a4ca58..0000000000 --- a/patches/server/0704-Dont-resent-entity-on-art-update.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 8 Jun 2022 11:04:47 -0400 -Subject: [PATCH] Dont resent entity on art update - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -index dd02cec9a82794a6b001c3b64f031f78d5fbb812..bcac1359c667ef1ee46384f9c7a5adf4010d2b08 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -@@ -36,7 +36,7 @@ public class CraftPainting extends CraftHanging implements Painting { - painting.setDirection(painting.getDirection()); - return false; - } -- this.update(); -+ //this.update(); Paper - Don't resent entity on art update - return true; - } - diff --git a/patches/server/0705-Add-WardenAngerChangeEvent.patch b/patches/server/0705-Add-WardenAngerChangeEvent.patch deleted file mode 100644 index ca2817ab51..0000000000 --- a/patches/server/0705-Add-WardenAngerChangeEvent.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nopjar -Date: Sun, 12 Jun 2022 02:26:04 +0200 -Subject: [PATCH] Add WardenAngerChangeEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java b/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java -index 27e52ee93ab591e97f37705de64cb5b62c06e253..3d792957f27fd4bdfad8d76262a8e2a2012bf35f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java -+++ b/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java -@@ -146,7 +146,7 @@ public class AngerManagement { - - public int increaseAnger(Entity entity, int amount) { - boolean bl = !this.angerBySuspect.containsKey(entity); -- int i = this.angerBySuspect.computeInt(entity, (suspect, anger) -> Math.min(150, (anger == null ? 0 : anger) + amount)); -+ int i = this.angerBySuspect.computeInt(entity, (suspect, anger) -> Math.min(150, (anger == null ? 0 : anger) + amount)); // Paper - diff on change (Warden#increaseAngerAt WardenAngerChangeEvent) - if (bl) { - int j = this.angerByUuid.removeInt(entity.getUUID()); - i += j; -diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 71311d30459d495c57e6fcf0115e4f34a232f1ad..6180019da58b19d2595da508aed3196af922d587 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -+++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -@@ -482,6 +482,15 @@ public class Warden extends Monster implements VibrationSystem { - @VisibleForTesting - public void increaseAngerAt(@Nullable Entity entity, int amount, boolean listening) { - if (!this.isNoAi() && this.canTargetEntity(entity)) { -+ // Paper start - Add WardenAngerChangeEvent -+ int activeAnger = this.angerManagement.getActiveAnger(entity); -+ io.papermc.paper.event.entity.WardenAngerChangeEvent event = new io.papermc.paper.event.entity.WardenAngerChangeEvent((org.bukkit.entity.Warden) this.getBukkitEntity(), entity.getBukkitEntity(), activeAnger, Math.min(150, activeAnger + amount)); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ return; -+ } -+ amount = event.getNewAnger() - activeAnger; -+ // Paper end - Add WardenAngerChangeEvent - WardenAi.setDigCooldown(this); - boolean flag1 = !(this.getTarget() instanceof Player); - int j = this.angerManagement.increaseAnger(entity, amount); diff --git a/patches/server/0705-Add-option-for-strict-advancement-dimension-checks.patch b/patches/server/0705-Add-option-for-strict-advancement-dimension-checks.patch new file mode 100644 index 0000000000..ca19dca53f --- /dev/null +++ b/patches/server/0705-Add-option-for-strict-advancement-dimension-checks.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 12 Jun 2022 11:47:24 -0700 +Subject: [PATCH] Add option for strict advancement dimension checks + +Craftbukkit attempts to translate worlds that use the +same generation as the Overworld, The Nether, or The End +to use those dimensions when checking the `changed_dimension` +criteria trigger, or whether to trigger the `NETHER_TRAVEL` +distance trigger. This adds a config option to ignore that +and use the exact dimension key of the worlds involved. + +diff --git a/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java b/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java +index 01b8f7024fbc965bc6a7f97f79ba3dec964ef769..801823d003a8e28a13fe90db4604cd0938899c6d 100644 +--- a/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java ++++ b/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java +@@ -44,7 +44,7 @@ public record LocationPredicate( + public boolean matches(ServerLevel world, double x, double y, double z) { + if (this.position.isPresent() && !this.position.get().matches(x, y, z)) { + return false; +- } else if (this.dimension.isPresent() && this.dimension.get() != world.dimension()) { ++ } else if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? world.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(world))) { // Paper - Add option for strict advancement dimension checks + return false; + } else { + BlockPos blockPos = BlockPos.containing(x, y, z); +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index d723adaa7b1df4a1d5067298536b303992ac2c52..312225a15261f2e80fbf6133c75c567574ade181 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1655,6 +1655,12 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + ResourceKey maindimensionkey = CraftDimensionUtil.getMainDimensionKey(origin); + ResourceKey maindimensionkey1 = CraftDimensionUtil.getMainDimensionKey(this.level()); + ++ // Paper start - Add option for strict advancement dimension checks ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck) { ++ maindimensionkey = resourcekey; ++ maindimensionkey1 = resourcekey1; ++ } ++ // Paper end - Add option for strict advancement dimension checks + CriteriaTriggers.CHANGED_DIMENSION.trigger(this, maindimensionkey, maindimensionkey1); + if (maindimensionkey != resourcekey || maindimensionkey1 != resourcekey1) { + CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourcekey, resourcekey1); diff --git a/patches/server/0706-Add-missing-important-BlockStateListPopulator-method.patch b/patches/server/0706-Add-missing-important-BlockStateListPopulator-method.patch new file mode 100644 index 0000000000..e0b94dc4ac --- /dev/null +++ b/patches/server/0706-Add-missing-important-BlockStateListPopulator-method.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 12 Jun 2022 13:25:52 -0400 +Subject: [PATCH] Add missing important BlockStateListPopulator methods + +Without these methods it causes exceptions due to these being used by certain feature generators. + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java +index 072d105f05f3b535d53cfbf8538d1716f9cfcd0e..4d6d637188ef4010a71ea2eb6ea0310aea820511 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java +@@ -129,7 +129,7 @@ public class BlockStateListPopulator extends DummyGeneratorAccess { + + @Override + public boolean isFluidAtPosition(BlockPos pos, Predicate state) { +- return this.world.isFluidAtPosition(pos, state); ++ return state.test(this.getFluidState(pos)); // Paper - fix + } + + @Override +@@ -152,4 +152,33 @@ public class BlockStateListPopulator extends DummyGeneratorAccess { + public long nextSubTickCount() { + return this.world.nextSubTickCount(); + } ++ ++ // Paper start ++ @Override ++ public java.util.Optional getBlockEntity(BlockPos pos, net.minecraft.world.level.block.entity.BlockEntityType type) { ++ BlockEntity tileentity = this.getBlockEntity(pos); ++ ++ return tileentity != null && tileentity.getType() == type ? (java.util.Optional) java.util.Optional.of(tileentity) : java.util.Optional.empty(); ++ } ++ ++ @Override ++ public BlockPos getHeightmapPos(net.minecraft.world.level.levelgen.Heightmap.Types heightmap, BlockPos pos) { ++ return world.getHeightmapPos(heightmap, pos); ++ } ++ ++ @Override ++ public int getHeight(net.minecraft.world.level.levelgen.Heightmap.Types heightmap, int x, int z) { ++ return world.getHeight(heightmap, x, z); ++ } ++ ++ @Override ++ public int getRawBrightness(BlockPos pos, int ambientDarkness) { ++ return world.getRawBrightness(pos, ambientDarkness); ++ } ++ ++ @Override ++ public int getBrightness(net.minecraft.world.level.LightLayer type, BlockPos pos) { ++ return world.getBrightness(type, pos); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +index 4705aed1dd98378c146bf9e346df1a17f719ad36..daf3c26fce7569761951bfd5594c6726d854a9ff 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +@@ -258,4 +258,14 @@ public class DummyGeneratorAccess implements WorldGenLevel { + public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth) { + return false; // SPIGOT-6515 + } ++ ++ // Paper start - add more methods ++ public void scheduleTick(BlockPos pos, Fluid fluid, int delay) {} ++ ++ @Override ++ public void scheduleTick(BlockPos pos, Block block, int delay, net.minecraft.world.ticks.TickPriority priority) {} ++ ++ @Override ++ public void scheduleTick(BlockPos pos, Fluid fluid, int delay, net.minecraft.world.ticks.TickPriority priority) {} ++ // Paper end - add more methods + } diff --git a/patches/server/0706-Add-option-for-strict-advancement-dimension-checks.patch b/patches/server/0706-Add-option-for-strict-advancement-dimension-checks.patch deleted file mode 100644 index ca19dca53f..0000000000 --- a/patches/server/0706-Add-option-for-strict-advancement-dimension-checks.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 12 Jun 2022 11:47:24 -0700 -Subject: [PATCH] Add option for strict advancement dimension checks - -Craftbukkit attempts to translate worlds that use the -same generation as the Overworld, The Nether, or The End -to use those dimensions when checking the `changed_dimension` -criteria trigger, or whether to trigger the `NETHER_TRAVEL` -distance trigger. This adds a config option to ignore that -and use the exact dimension key of the worlds involved. - -diff --git a/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java b/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java -index 01b8f7024fbc965bc6a7f97f79ba3dec964ef769..801823d003a8e28a13fe90db4604cd0938899c6d 100644 ---- a/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java -+++ b/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java -@@ -44,7 +44,7 @@ public record LocationPredicate( - public boolean matches(ServerLevel world, double x, double y, double z) { - if (this.position.isPresent() && !this.position.get().matches(x, y, z)) { - return false; -- } else if (this.dimension.isPresent() && this.dimension.get() != world.dimension()) { -+ } else if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? world.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(world))) { // Paper - Add option for strict advancement dimension checks - return false; - } else { - BlockPos blockPos = BlockPos.containing(x, y, z); -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index d723adaa7b1df4a1d5067298536b303992ac2c52..312225a15261f2e80fbf6133c75c567574ade181 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1655,6 +1655,12 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - ResourceKey maindimensionkey = CraftDimensionUtil.getMainDimensionKey(origin); - ResourceKey maindimensionkey1 = CraftDimensionUtil.getMainDimensionKey(this.level()); - -+ // Paper start - Add option for strict advancement dimension checks -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck) { -+ maindimensionkey = resourcekey; -+ maindimensionkey1 = resourcekey1; -+ } -+ // Paper end - Add option for strict advancement dimension checks - CriteriaTriggers.CHANGED_DIMENSION.trigger(this, maindimensionkey, maindimensionkey1); - if (maindimensionkey != resourcekey || maindimensionkey1 != resourcekey1) { - CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourcekey, resourcekey1); diff --git a/patches/server/0707-Add-missing-important-BlockStateListPopulator-method.patch b/patches/server/0707-Add-missing-important-BlockStateListPopulator-method.patch deleted file mode 100644 index e0b94dc4ac..0000000000 --- a/patches/server/0707-Add-missing-important-BlockStateListPopulator-method.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 12 Jun 2022 13:25:52 -0400 -Subject: [PATCH] Add missing important BlockStateListPopulator methods - -Without these methods it causes exceptions due to these being used by certain feature generators. - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java -index 072d105f05f3b535d53cfbf8538d1716f9cfcd0e..4d6d637188ef4010a71ea2eb6ea0310aea820511 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java -@@ -129,7 +129,7 @@ public class BlockStateListPopulator extends DummyGeneratorAccess { - - @Override - public boolean isFluidAtPosition(BlockPos pos, Predicate state) { -- return this.world.isFluidAtPosition(pos, state); -+ return state.test(this.getFluidState(pos)); // Paper - fix - } - - @Override -@@ -152,4 +152,33 @@ public class BlockStateListPopulator extends DummyGeneratorAccess { - public long nextSubTickCount() { - return this.world.nextSubTickCount(); - } -+ -+ // Paper start -+ @Override -+ public java.util.Optional getBlockEntity(BlockPos pos, net.minecraft.world.level.block.entity.BlockEntityType type) { -+ BlockEntity tileentity = this.getBlockEntity(pos); -+ -+ return tileentity != null && tileentity.getType() == type ? (java.util.Optional) java.util.Optional.of(tileentity) : java.util.Optional.empty(); -+ } -+ -+ @Override -+ public BlockPos getHeightmapPos(net.minecraft.world.level.levelgen.Heightmap.Types heightmap, BlockPos pos) { -+ return world.getHeightmapPos(heightmap, pos); -+ } -+ -+ @Override -+ public int getHeight(net.minecraft.world.level.levelgen.Heightmap.Types heightmap, int x, int z) { -+ return world.getHeight(heightmap, x, z); -+ } -+ -+ @Override -+ public int getRawBrightness(BlockPos pos, int ambientDarkness) { -+ return world.getRawBrightness(pos, ambientDarkness); -+ } -+ -+ @Override -+ public int getBrightness(net.minecraft.world.level.LightLayer type, BlockPos pos) { -+ return world.getBrightness(type, pos); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -index 4705aed1dd98378c146bf9e346df1a17f719ad36..daf3c26fce7569761951bfd5594c6726d854a9ff 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -@@ -258,4 +258,14 @@ public class DummyGeneratorAccess implements WorldGenLevel { - public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth) { - return false; // SPIGOT-6515 - } -+ -+ // Paper start - add more methods -+ public void scheduleTick(BlockPos pos, Fluid fluid, int delay) {} -+ -+ @Override -+ public void scheduleTick(BlockPos pos, Block block, int delay, net.minecraft.world.ticks.TickPriority priority) {} -+ -+ @Override -+ public void scheduleTick(BlockPos pos, Fluid fluid, int delay, net.minecraft.world.ticks.TickPriority priority) {} -+ // Paper end - add more methods - } diff --git a/patches/server/0707-Nameable-Banner-API.patch b/patches/server/0707-Nameable-Banner-API.patch new file mode 100644 index 0000000000..aab360dbed --- /dev/null +++ b/patches/server/0707-Nameable-Banner-API.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Thu, 7 Apr 2022 17:49:25 -0400 +Subject: [PATCH] Nameable Banner API + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java +index 01521f38871d821762ff7ac2d39927f8c6b861bf..98bc87fe5d153cc4927f7e1b4a02f61d9dd019a0 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java +@@ -29,7 +29,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable { + public static final int MAX_PATTERNS = 6; + private static final String TAG_PATTERNS = "patterns"; + @Nullable +- private Component name; ++ public Component name; // Paper - public + public DyeColor baseColor; + private BannerPatternLayers patterns; + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java +index 5635230fc288fe5280bf785b42c862b8f111afb0..afed8bdb9bd6a135e9b5f7bd9bfc61964cb240f7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java +@@ -112,4 +112,26 @@ public class CraftBanner extends CraftBlockEntityState implem + public CraftBanner copy(Location location) { + return new CraftBanner(this, location); + } ++ ++ // Paper start ++ @Override ++ public net.kyori.adventure.text.Component customName() { ++ return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getSnapshot().getCustomName()); ++ } ++ ++ @Override ++ public void customName(net.kyori.adventure.text.Component customName) { ++ this.getSnapshot().name = io.papermc.paper.adventure.PaperAdventure.asVanilla(customName); ++ } ++ ++ @Override ++ public String getCustomName() { ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(this.customName()); ++ } ++ ++ @Override ++ public void setCustomName(String name) { ++ this.customName(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(name)); ++ } ++ // Paper end + } diff --git a/patches/server/0708-Don-t-broadcast-messages-to-command-blocks.patch b/patches/server/0708-Don-t-broadcast-messages-to-command-blocks.patch new file mode 100644 index 0000000000..428c5de1aa --- /dev/null +++ b/patches/server/0708-Don-t-broadcast-messages-to-command-blocks.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 16 Jun 2022 14:22:56 -0700 +Subject: [PATCH] Don't broadcast messages to command blocks + +Previously the broadcast method would update the last output +in command blocks, and if called asynchronously, would throw +an error + +diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java +index a0e59b236dff1f861a0e987764a77ee203504412..5cb39f95bd2d45b6c18554605f01d2ebf6473428 100644 +--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java ++++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java +@@ -178,6 +178,7 @@ public abstract class BaseCommandBlock implements CommandSource { + @Override + public void sendSystemMessage(Component message) { + if (this.trackOutput) { ++ org.spigotmc.AsyncCatcher.catchOp("sendSystemMessage to a command block"); // Paper - Don't broadcast messages to command blocks + SimpleDateFormat simpledateformat = BaseCommandBlock.TIME_FORMAT; + Date date = new Date(); + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 2d16e96c7c329cde6369f1d5b739f60f1776bb4b..3deb58f3cd2e29b51944ac81cb3e0e52ec496242 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1928,7 +1928,7 @@ public final class CraftServer implements Server { + // Paper end + Set recipients = new HashSet<>(); + for (Permissible permissible : this.getPluginManager().getPermissionSubscriptions(permission)) { +- if (permissible instanceof CommandSender && permissible.hasPermission(permission)) { ++ if (permissible instanceof CommandSender && !(permissible instanceof org.bukkit.command.BlockCommandSender) && permissible.hasPermission(permission)) { // Paper - Don't broadcast messages to command blocks + recipients.add((CommandSender) permissible); + } + } diff --git a/patches/server/0708-Nameable-Banner-API.patch b/patches/server/0708-Nameable-Banner-API.patch deleted file mode 100644 index aab360dbed..0000000000 --- a/patches/server/0708-Nameable-Banner-API.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Thu, 7 Apr 2022 17:49:25 -0400 -Subject: [PATCH] Nameable Banner API - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java -index 01521f38871d821762ff7ac2d39927f8c6b861bf..98bc87fe5d153cc4927f7e1b4a02f61d9dd019a0 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java -@@ -29,7 +29,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable { - public static final int MAX_PATTERNS = 6; - private static final String TAG_PATTERNS = "patterns"; - @Nullable -- private Component name; -+ public Component name; // Paper - public - public DyeColor baseColor; - private BannerPatternLayers patterns; - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java -index 5635230fc288fe5280bf785b42c862b8f111afb0..afed8bdb9bd6a135e9b5f7bd9bfc61964cb240f7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java -@@ -112,4 +112,26 @@ public class CraftBanner extends CraftBlockEntityState implem - public CraftBanner copy(Location location) { - return new CraftBanner(this, location); - } -+ -+ // Paper start -+ @Override -+ public net.kyori.adventure.text.Component customName() { -+ return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getSnapshot().getCustomName()); -+ } -+ -+ @Override -+ public void customName(net.kyori.adventure.text.Component customName) { -+ this.getSnapshot().name = io.papermc.paper.adventure.PaperAdventure.asVanilla(customName); -+ } -+ -+ @Override -+ public String getCustomName() { -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(this.customName()); -+ } -+ -+ @Override -+ public void setCustomName(String name) { -+ this.customName(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(name)); -+ } -+ // Paper end - } diff --git a/patches/server/0709-Don-t-broadcast-messages-to-command-blocks.patch b/patches/server/0709-Don-t-broadcast-messages-to-command-blocks.patch deleted file mode 100644 index dc36254227..0000000000 --- a/patches/server/0709-Don-t-broadcast-messages-to-command-blocks.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 16 Jun 2022 14:22:56 -0700 -Subject: [PATCH] Don't broadcast messages to command blocks - -Previously the broadcast method would update the last output -in command blocks, and if called asynchronously, would throw -an error - -diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -index a0e59b236dff1f861a0e987764a77ee203504412..5cb39f95bd2d45b6c18554605f01d2ebf6473428 100644 ---- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -@@ -178,6 +178,7 @@ public abstract class BaseCommandBlock implements CommandSource { - @Override - public void sendSystemMessage(Component message) { - if (this.trackOutput) { -+ org.spigotmc.AsyncCatcher.catchOp("sendSystemMessage to a command block"); // Paper - Don't broadcast messages to command blocks - SimpleDateFormat simpledateformat = BaseCommandBlock.TIME_FORMAT; - Date date = new Date(); - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index f2898c356182fee8a1f525ab762d9c126d2108fc..0c037618005265ed6b9533ea60848753141d8e0b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1929,7 +1929,7 @@ public final class CraftServer implements Server { - // Paper end - Set recipients = new HashSet<>(); - for (Permissible permissible : this.getPluginManager().getPermissionSubscriptions(permission)) { -- if (permissible instanceof CommandSender && permissible.hasPermission(permission)) { -+ if (permissible instanceof CommandSender && !(permissible instanceof org.bukkit.command.BlockCommandSender) && permissible.hasPermission(permission)) { // Paper - Don't broadcast messages to command blocks - recipients.add((CommandSender) permissible); - } - } diff --git a/patches/server/0709-Prevent-empty-items-from-being-added-to-world.patch b/patches/server/0709-Prevent-empty-items-from-being-added-to-world.patch new file mode 100644 index 0000000000..4b6241c770 --- /dev/null +++ b/patches/server/0709-Prevent-empty-items-from-being-added-to-world.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 15 Jun 2022 21:52:57 -0400 +Subject: [PATCH] Prevent empty items from being added to world + +The previous solution caused a bunch of bandaid fixes inorder to resolve edge cases where minecraft/the api might spawn items that are air. +Just simply prevent them from being added to the world instead. + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index f4b1b5f1903015b3c4650186466c8183560c9de0..f3f93e8cbc2a5c9d0a3841ec7de010477bfd976a 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1200,6 +1200,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit + return false; + } else { ++ if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added + // Paper start - capture all item additions to the world + if (captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) { + captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity); diff --git a/patches/server/0710-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch b/patches/server/0710-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch new file mode 100644 index 0000000000..c2e21a749e --- /dev/null +++ b/patches/server/0710-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 21 Apr 2022 18:18:02 -0700 +Subject: [PATCH] Fix CCE for SplashPotion and LingeringPotion spawning + +Remove in 1.19 along with the SplashPotion and +LingeringPotion interfaces + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java +index f6fa6f1ac50b757dd3bc9a8dee9f6085446182c8..65b6de9d21da6843d7c7087f0dea98d3b75f24cf 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java +@@ -14,7 +14,7 @@ import org.bukkit.entity.ThrownPotion; + import org.bukkit.inventory.ItemStack; + import org.bukkit.potion.PotionEffect; + +-public class CraftThrownPotion extends CraftThrowableProjectile implements ThrownPotion { ++public class CraftThrownPotion extends CraftThrowableProjectile implements ThrownPotion, org.bukkit.entity.SplashPotion, org.bukkit.entity.LingeringPotion { // Paper - implement other classes to avoid violating spawn method generic contracts + public CraftThrownPotion(CraftServer server, net.minecraft.world.entity.projectile.ThrownPotion entity) { + super(server, entity); + } diff --git a/patches/server/0710-Prevent-empty-items-from-being-added-to-world.patch b/patches/server/0710-Prevent-empty-items-from-being-added-to-world.patch deleted file mode 100644 index 9c65327919..0000000000 --- a/patches/server/0710-Prevent-empty-items-from-being-added-to-world.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 15 Jun 2022 21:52:57 -0400 -Subject: [PATCH] Prevent empty items from being added to world - -The previous solution caused a bunch of bandaid fixes inorder to resolve edge cases where minecraft/the api might spawn items that are air. -Just simply prevent them from being added to the world instead. - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index cb33c53d441d2d535b48cb80f5ac445b52cd98be..f9f00a3862ab829e7695b1da484cb752bdef5c4f 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1230,6 +1230,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit - return false; - } else { -+ if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added - // Paper start - capture all item additions to the world - if (captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) { - captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity); diff --git a/patches/server/0711-Add-Player-getFishHook.patch b/patches/server/0711-Add-Player-getFishHook.patch new file mode 100644 index 0000000000..b2f8e7f0eb --- /dev/null +++ b/patches/server/0711-Add-Player-getFishHook.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: u9g +Date: Tue, 14 Jun 2022 19:36:10 -0400 +Subject: [PATCH] Add Player#getFishHook + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index 1e49eae80730aa9d2e49cd92759d899deb49fb90..df9d02eb1ffc3cc669e835e2c08d951283871db3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -160,6 +160,15 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + return new Location(worldServer.getWorld(), bed.getX(), bed.getY(), bed.getZ()); + } + // Paper end ++ // Paper start ++ @Override ++ public org.bukkit.entity.FishHook getFishHook() { ++ if (getHandle().fishing == null) { ++ return null; ++ } ++ return (org.bukkit.entity.FishHook) getHandle().fishing.getBukkitEntity(); ++ } ++ // Paper end + @Override + public boolean sleep(Location location, boolean force) { + Preconditions.checkArgument(location != null, "Location cannot be null"); diff --git a/patches/server/0711-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch b/patches/server/0711-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch deleted file mode 100644 index c2e21a749e..0000000000 --- a/patches/server/0711-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 21 Apr 2022 18:18:02 -0700 -Subject: [PATCH] Fix CCE for SplashPotion and LingeringPotion spawning - -Remove in 1.19 along with the SplashPotion and -LingeringPotion interfaces - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java -index f6fa6f1ac50b757dd3bc9a8dee9f6085446182c8..65b6de9d21da6843d7c7087f0dea98d3b75f24cf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java -@@ -14,7 +14,7 @@ import org.bukkit.entity.ThrownPotion; - import org.bukkit.inventory.ItemStack; - import org.bukkit.potion.PotionEffect; - --public class CraftThrownPotion extends CraftThrowableProjectile implements ThrownPotion { -+public class CraftThrownPotion extends CraftThrowableProjectile implements ThrownPotion, org.bukkit.entity.SplashPotion, org.bukkit.entity.LingeringPotion { // Paper - implement other classes to avoid violating spawn method generic contracts - public CraftThrownPotion(CraftServer server, net.minecraft.world.entity.projectile.ThrownPotion entity) { - super(server, entity); - } diff --git a/patches/server/0712-Add-Player-getFishHook.patch b/patches/server/0712-Add-Player-getFishHook.patch deleted file mode 100644 index b2f8e7f0eb..0000000000 --- a/patches/server/0712-Add-Player-getFishHook.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: u9g -Date: Tue, 14 Jun 2022 19:36:10 -0400 -Subject: [PATCH] Add Player#getFishHook - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 1e49eae80730aa9d2e49cd92759d899deb49fb90..df9d02eb1ffc3cc669e835e2c08d951283871db3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -160,6 +160,15 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - return new Location(worldServer.getWorld(), bed.getX(), bed.getY(), bed.getZ()); - } - // Paper end -+ // Paper start -+ @Override -+ public org.bukkit.entity.FishHook getFishHook() { -+ if (getHandle().fishing == null) { -+ return null; -+ } -+ return (org.bukkit.entity.FishHook) getHandle().fishing.getBukkitEntity(); -+ } -+ // Paper end - @Override - public boolean sleep(Location location, boolean force) { - Preconditions.checkArgument(location != null, "Location cannot be null"); diff --git a/patches/server/0712-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch b/patches/server/0712-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch new file mode 100644 index 0000000000..32aaf6dc6e --- /dev/null +++ b/patches/server/0712-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 3 Jul 2022 22:31:37 -0700 +Subject: [PATCH] Do not sync load chunk for dynamic game event listener + registration + +These can be called while an entity is being added to the world, +and if the entity is being added from a chunk load context the +sync load will block indefinitely (because the chunk load context +is for completing the chunk to FULL). + +This does raise questions about the current system for these +dynamic registrations, as it looks like there is _zero_ logic +to account for the case where the chunk is _not_ currently loaded +and then later loaded. + +diff --git a/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java b/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java +index af9437bddf69546a1a78eca7e858ac8d2e68ed0a..134b4ceec0ec5a2475881e739d6579fa5984c3dd 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java +@@ -41,7 +41,7 @@ public class DynamicGameEventListener { + + private static void ifChunkExists(LevelReader world, @Nullable SectionPos sectionPos, Consumer dispatcherConsumer) { + if (sectionPos != null) { +- ChunkAccess chunkAccess = world.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.FULL, false); ++ ChunkAccess chunkAccess = world.getChunkIfLoadedImmediately(sectionPos.getX(), sectionPos.getZ()); // Paper - Perf: can cause sync loads while completing a chunk, resulting in deadlock + if (chunkAccess != null) { + dispatcherConsumer.accept(chunkAccess.getListenerRegistry(sectionPos.y())); + } diff --git a/patches/server/0713-Add-various-missing-EntityDropItemEvent-calls.patch b/patches/server/0713-Add-various-missing-EntityDropItemEvent-calls.patch new file mode 100644 index 0000000000..8e1fc7a091 --- /dev/null +++ b/patches/server/0713-Add-various-missing-EntityDropItemEvent-calls.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 20 Jul 2021 21:35:47 -0700 +Subject: [PATCH] Add various missing EntityDropItemEvent calls + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 73428cefa737e430c3c8c0d59e1fa763114b8c5a..619879bc0a05e16d450b4f7bb766b371e986193c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2672,6 +2672,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe + + entityitem.setDefaultPickUpDelay(); ++ // Paper start - Call EntityDropItemEvent ++ return this.spawnAtLocation(world, entityitem); ++ } ++ } ++ @Nullable ++ public ItemEntity spawnAtLocation(ServerLevel world, ItemEntity entityitem) { ++ { ++ // Paper end - Call EntityDropItemEvent + // CraftBukkit start + EntityDropItemEvent event = new EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); + Bukkit.getPluginManager().callEvent(event); +diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java +index dde1ccca98f58200910334160f0f79eb00dd2388..5af4d590a9b0f17ba53c6959d9c18bd1269878a4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java +@@ -604,7 +604,7 @@ public class Dolphin extends AgeableWaterCreature { + float f2 = 0.02F * Dolphin.this.random.nextFloat(); + + entityitem.setDeltaMovement((double) (0.3F * -Mth.sin(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.cos(f1) * f2), (double) (0.3F * Mth.sin(Dolphin.this.getXRot() * 0.017453292F) * 1.5F), (double) (0.3F * Mth.cos(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.sin(f1) * f2)); +- Dolphin.this.level().addFreshEntity(entityitem); ++ Dolphin.this.spawnAtLocation(getServerLevel(Dolphin.this), entityitem); // Paper - Call EntityDropItemEvent + } + } + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java +index 205aefd38a185fa411ff17cfb0155769de8fc2fd..67ea374ae3c66af434b4aadbe702a44d230fbe09 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java +@@ -492,14 +492,14 @@ public class Fox extends Animal implements VariantHolder { + entityitem.setPickUpDelay(40); + entityitem.setThrower(this); + this.playSound(SoundEvents.FOX_SPIT, 1.0F, 1.0F); +- this.level().addFreshEntity(entityitem); ++ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem); // Paper - Call EntityDropItemEvent + } + } + + private void dropItemStack(ItemStack stack) { + ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), stack); + +- this.level().addFreshEntity(entityitem); ++ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem); // Paper - Call EntityDropItemEvent + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +index 14e02f9b0169db8388c515a68315ad5cc3f13d22..14b47d6fa189f2a666b12ef7e7708d204c2b0452 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +@@ -365,8 +365,7 @@ public class Goat extends Animal { + double d2 = (double) Mth.randomBetween(this.random, -0.2F, 0.2F); + ItemEntity entityitem = new ItemEntity(this.level(), vec3d.x(), vec3d.y(), vec3d.z(), itemstack, d0, d1, d2); + +- this.level().addFreshEntity(entityitem); +- return true; ++ return this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem) != null; // Paper - Call EntityDropItemEvent + } + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java +index 5e586f174ff4b610a2584f28c9ffdd445ad58bea..014e1ea1603bc7a7b42ae7ff7d12e5a41f331d2f 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java ++++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java +@@ -345,8 +345,9 @@ public class Sniffer extends Animal { + + entityitem.setDefaultPickUpDelay(); + this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null); ++ if (this.spawnAtLocation(world, entityitem) != null) { // Paper - Call EntityDropItemEvent + this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F); +- world.addFreshEntity(entityitem); ++ } // Paper - Call EntityDropItemEvent + } + + @Override +diff --git a/src/main/java/net/minecraft/world/item/ItemUtils.java b/src/main/java/net/minecraft/world/item/ItemUtils.java +index f4fc17e029407be5df3cfe2dcb6fb2f88234b066..0c4074ed8b4fd9d6fcb838e8843d66f6f286ed5d 100644 +--- a/src/main/java/net/minecraft/world/item/ItemUtils.java ++++ b/src/main/java/net/minecraft/world/item/ItemUtils.java +@@ -41,7 +41,15 @@ public class ItemUtils { + public static void onContainerDestroyed(ItemEntity itemEntity, Iterable contents) { + Level level = itemEntity.level(); + if (!level.isClientSide) { +- contents.forEach(stack -> level.addFreshEntity(new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack))); ++ // Paper start - call EntityDropItemEvent ++ contents.forEach(stack -> { ++ ItemEntity droppedItem = new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack); ++ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(itemEntity.getBukkitEntity(), (org.bukkit.entity.Item) droppedItem.getBukkitEntity()); ++ if (event.callEvent()) { ++ level.addFreshEntity(droppedItem); ++ } ++ }); ++ // Paper end - call EntityDropItemEvent + } + } + } diff --git a/patches/server/0713-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch b/patches/server/0713-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch deleted file mode 100644 index 32aaf6dc6e..0000000000 --- a/patches/server/0713-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 3 Jul 2022 22:31:37 -0700 -Subject: [PATCH] Do not sync load chunk for dynamic game event listener - registration - -These can be called while an entity is being added to the world, -and if the entity is being added from a chunk load context the -sync load will block indefinitely (because the chunk load context -is for completing the chunk to FULL). - -This does raise questions about the current system for these -dynamic registrations, as it looks like there is _zero_ logic -to account for the case where the chunk is _not_ currently loaded -and then later loaded. - -diff --git a/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java b/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java -index af9437bddf69546a1a78eca7e858ac8d2e68ed0a..134b4ceec0ec5a2475881e739d6579fa5984c3dd 100644 ---- a/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java -+++ b/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java -@@ -41,7 +41,7 @@ public class DynamicGameEventListener { - - private static void ifChunkExists(LevelReader world, @Nullable SectionPos sectionPos, Consumer dispatcherConsumer) { - if (sectionPos != null) { -- ChunkAccess chunkAccess = world.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.FULL, false); -+ ChunkAccess chunkAccess = world.getChunkIfLoadedImmediately(sectionPos.getX(), sectionPos.getZ()); // Paper - Perf: can cause sync loads while completing a chunk, resulting in deadlock - if (chunkAccess != null) { - dispatcherConsumer.accept(chunkAccess.getListenerRegistry(sectionPos.y())); - } diff --git a/patches/server/0714-Add-various-missing-EntityDropItemEvent-calls.patch b/patches/server/0714-Add-various-missing-EntityDropItemEvent-calls.patch deleted file mode 100644 index 8e1fc7a091..0000000000 --- a/patches/server/0714-Add-various-missing-EntityDropItemEvent-calls.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 20 Jul 2021 21:35:47 -0700 -Subject: [PATCH] Add various missing EntityDropItemEvent calls - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 73428cefa737e430c3c8c0d59e1fa763114b8c5a..619879bc0a05e16d450b4f7bb766b371e986193c 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2672,6 +2672,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe - - entityitem.setDefaultPickUpDelay(); -+ // Paper start - Call EntityDropItemEvent -+ return this.spawnAtLocation(world, entityitem); -+ } -+ } -+ @Nullable -+ public ItemEntity spawnAtLocation(ServerLevel world, ItemEntity entityitem) { -+ { -+ // Paper end - Call EntityDropItemEvent - // CraftBukkit start - EntityDropItemEvent event = new EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); - Bukkit.getPluginManager().callEvent(event); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -index dde1ccca98f58200910334160f0f79eb00dd2388..5af4d590a9b0f17ba53c6959d9c18bd1269878a4 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -@@ -604,7 +604,7 @@ public class Dolphin extends AgeableWaterCreature { - float f2 = 0.02F * Dolphin.this.random.nextFloat(); - - entityitem.setDeltaMovement((double) (0.3F * -Mth.sin(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.cos(f1) * f2), (double) (0.3F * Mth.sin(Dolphin.this.getXRot() * 0.017453292F) * 1.5F), (double) (0.3F * Mth.cos(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.sin(f1) * f2)); -- Dolphin.this.level().addFreshEntity(entityitem); -+ Dolphin.this.spawnAtLocation(getServerLevel(Dolphin.this), entityitem); // Paper - Call EntityDropItemEvent - } - } - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index 205aefd38a185fa411ff17cfb0155769de8fc2fd..67ea374ae3c66af434b4aadbe702a44d230fbe09 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Fox.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java -@@ -492,14 +492,14 @@ public class Fox extends Animal implements VariantHolder { - entityitem.setPickUpDelay(40); - entityitem.setThrower(this); - this.playSound(SoundEvents.FOX_SPIT, 1.0F, 1.0F); -- this.level().addFreshEntity(entityitem); -+ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem); // Paper - Call EntityDropItemEvent - } - } - - private void dropItemStack(ItemStack stack) { - ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), stack); - -- this.level().addFreshEntity(entityitem); -+ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem); // Paper - Call EntityDropItemEvent - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 14e02f9b0169db8388c515a68315ad5cc3f13d22..14b47d6fa189f2a666b12ef7e7708d204c2b0452 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -365,8 +365,7 @@ public class Goat extends Animal { - double d2 = (double) Mth.randomBetween(this.random, -0.2F, 0.2F); - ItemEntity entityitem = new ItemEntity(this.level(), vec3d.x(), vec3d.y(), vec3d.z(), itemstack, d0, d1, d2); - -- this.level().addFreshEntity(entityitem); -- return true; -+ return this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem) != null; // Paper - Call EntityDropItemEvent - } - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -index 5e586f174ff4b610a2584f28c9ffdd445ad58bea..014e1ea1603bc7a7b42ae7ff7d12e5a41f331d2f 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -+++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -@@ -345,8 +345,9 @@ public class Sniffer extends Animal { - - entityitem.setDefaultPickUpDelay(); - this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null); -+ if (this.spawnAtLocation(world, entityitem) != null) { // Paper - Call EntityDropItemEvent - this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F); -- world.addFreshEntity(entityitem); -+ } // Paper - Call EntityDropItemEvent - } - - @Override -diff --git a/src/main/java/net/minecraft/world/item/ItemUtils.java b/src/main/java/net/minecraft/world/item/ItemUtils.java -index f4fc17e029407be5df3cfe2dcb6fb2f88234b066..0c4074ed8b4fd9d6fcb838e8843d66f6f286ed5d 100644 ---- a/src/main/java/net/minecraft/world/item/ItemUtils.java -+++ b/src/main/java/net/minecraft/world/item/ItemUtils.java -@@ -41,7 +41,15 @@ public class ItemUtils { - public static void onContainerDestroyed(ItemEntity itemEntity, Iterable contents) { - Level level = itemEntity.level(); - if (!level.isClientSide) { -- contents.forEach(stack -> level.addFreshEntity(new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack))); -+ // Paper start - call EntityDropItemEvent -+ contents.forEach(stack -> { -+ ItemEntity droppedItem = new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack); -+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(itemEntity.getBukkitEntity(), (org.bukkit.entity.Item) droppedItem.getBukkitEntity()); -+ if (event.callEvent()) { -+ level.addFreshEntity(droppedItem); -+ } -+ }); -+ // Paper end - call EntityDropItemEvent - } - } - } diff --git a/patches/server/0714-Fix-Bee-flower-NPE.patch b/patches/server/0714-Fix-Bee-flower-NPE.patch new file mode 100644 index 0000000000..d84bd3a355 --- /dev/null +++ b/patches/server/0714-Fix-Bee-flower-NPE.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 6 Jul 2022 14:59:38 -0700 +Subject: [PATCH] Fix Bee flower NPE + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java +index 048a357546c8f5ad5dbb86e2e1ada2730a52d061..42276acfeadec6e7aa9a91d3f446f4fedb04829d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java +@@ -940,7 +940,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + Bee.this.dropFlower(); + this.pollinating = false; + Bee.this.remainingCooldownBeforeLocatingNewFlower = 200; +- } else { ++ } else if (Bee.this.savedFlowerPos != null) { // Paper - add null check since API can manipulate this + Vec3 vec3d = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0D, 0.6000000238418579D, 0.0D); + + if (vec3d.distanceTo(Bee.this.position()) > 1.0D) { diff --git a/patches/server/0715-Fix-Bee-flower-NPE.patch b/patches/server/0715-Fix-Bee-flower-NPE.patch deleted file mode 100644 index d84bd3a355..0000000000 --- a/patches/server/0715-Fix-Bee-flower-NPE.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 6 Jul 2022 14:59:38 -0700 -Subject: [PATCH] Fix Bee flower NPE - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 048a357546c8f5ad5dbb86e2e1ada2730a52d061..42276acfeadec6e7aa9a91d3f446f4fedb04829d 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -940,7 +940,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - Bee.this.dropFlower(); - this.pollinating = false; - Bee.this.remainingCooldownBeforeLocatingNewFlower = 200; -- } else { -+ } else if (Bee.this.savedFlowerPos != null) { // Paper - add null check since API can manipulate this - Vec3 vec3d = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0D, 0.6000000238418579D, 0.0D); - - if (vec3d.distanceTo(Bee.this.position()) > 1.0D) { diff --git a/patches/server/0715-More-Teleport-API.patch b/patches/server/0715-More-Teleport-API.patch new file mode 100644 index 0000000000..7f4fab5c30 --- /dev/null +++ b/patches/server/0715-More-Teleport-API.patch @@ -0,0 +1,272 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 5 Sep 2021 12:15:59 -0400 +Subject: [PATCH] More Teleport API + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index bc8f9bd50de3894e6262e13ed55252c98f22ed8a..4d64eedfbe5b967572b7140ddfb55efa1ccc3650 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1585,11 +1585,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + return true; // CraftBukkit - Return event status + } + +- PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause); ++ // Paper start - Teleport API ++ Set relativeFlags = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class); ++ for (Relative relativeArgument : set) { ++ relativeFlags.add(org.bukkit.craftbukkit.entity.CraftPlayer.toApiRelativeFlag(relativeArgument)); ++ } ++ PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause, java.util.Set.copyOf(relativeFlags)); ++ // Paper end - Teleport API + this.cserver.getPluginManager().callEvent(event); + + if (event.isCancelled() || !to.equals(event.getTo())) { +- set = Collections.emptySet(); // Can't relative teleport ++ // set = Collections.emptySet(); // Can't relative teleport // Paper - Teleport API; Now you can! + to = event.isCancelled() ? event.getFrom() : event.getTo(); + positionmoverotation = new PositionMoveRotation(CraftLocation.toVec3D(to), Vec3.ZERO, to.getYaw(), to.getPitch()); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 4e6afa243d6108cb946a8a7cf96c4036a3c2ac0c..a314e401ee8a306dc12a2d98a3d400ae611a6e5a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -222,15 +222,36 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + + @Override + public boolean teleport(Location location, TeleportCause cause) { ++ // Paper start - Teleport passenger API ++ return teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]); ++ } ++ ++ @Override ++ public boolean teleport(Location location, TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { ++ // Paper end + Preconditions.checkArgument(location != null, "location cannot be null"); + location.checkFinite(); ++ // Paper start - Teleport passenger API ++ Set flagSet = Set.of(flags); ++ boolean dismount = !flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE); ++ boolean ignorePassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS); ++ // Don't allow teleporting between worlds while keeping passengers ++ if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) { ++ return false; ++ } ++ ++ // Don't allow to teleport between worlds if remaining on vehicle ++ if (!dismount && this.entity.isPassenger() && location.getWorld() != this.getWorld()) { ++ return false; ++ } ++ // Paper end + +- if (this.entity.isVehicle() || this.entity.isRemoved()) { ++ if ((!ignorePassengers && this.entity.isVehicle()) || this.entity.isRemoved()) { // Paper - Teleport passenger API + return false; + } + + // If this entity is riding another entity, we must dismount before teleporting. +- this.entity.stopRiding(); ++ if (dismount) this.entity.stopRiding(); // Paper - Teleport passenger API + + // Let the server handle cross world teleports + if (location.getWorld() != null && !location.getWorld().equals(this.getWorld())) { +@@ -976,6 +997,39 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return CraftEntity.perm; + } + ++ // Paper start - more teleport API / async chunk API ++ @Override ++ public java.util.concurrent.CompletableFuture teleportAsync(final Location location, final TeleportCause cause, final io.papermc.paper.entity.TeleportFlag... teleportFlags) { ++ Preconditions.checkArgument(location != null, "location"); ++ location.checkFinite(); ++ Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. ++ ++ net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle(); ++ java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); ++ ++ world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), ++ this instanceof CraftPlayer ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, (list) -> { ++ net.minecraft.server.level.ServerChunkCache chunkProviderServer = world.getChunkSource(); ++ for (net.minecraft.world.level.chunk.ChunkAccess chunk : list) { ++ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); ++ } ++ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { ++ try { ++ ret.complete(CraftEntity.this.teleport(locationClone, cause, teleportFlags) ? Boolean.TRUE : Boolean.FALSE); ++ } catch (Throwable throwable) { ++ if (throwable instanceof ThreadDeath) { ++ throw (ThreadDeath)throwable; ++ } ++ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to teleport entity " + CraftEntity.this, throwable); ++ ret.completeExceptionally(throwable); ++ } ++ }); ++ }); ++ ++ return ret; ++ } ++ // Paper end - more teleport API / async chunk API ++ + // Spigot start + private final org.bukkit.entity.Entity.Spigot spigot = new org.bukkit.entity.Entity.Spigot() + { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index fe0c355f8203c9bfa30d2ec48392a5a1a3d616ae..baae7a129853a296273b7f295f58cbb99187da22 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1303,13 +1303,102 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public void setRotation(float yaw, float pitch) { +- throw new UnsupportedOperationException("Cannot set rotation of players. Consider teleporting instead."); ++ // Paper start - Teleport API ++ Location targetLocation = this.getEyeLocation(); ++ targetLocation.setYaw(yaw); ++ targetLocation.setPitch(pitch); ++ ++ org.bukkit.util.Vector direction = targetLocation.getDirection(); ++ direction.multiply(9999999); // We need to move the target block.. FAR out ++ targetLocation.add(direction); ++ this.lookAt(targetLocation, io.papermc.paper.entity.LookAnchor.EYES); ++ // Paper end + } + + @Override + public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) { ++ // Paper start - Teleport API ++ return this.teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]); ++ } ++ ++ @Override ++ public void lookAt(@NotNull org.bukkit.entity.Entity entity, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor, @NotNull io.papermc.paper.entity.LookAnchor entityAnchor) { ++ this.getHandle().lookAt(toNmsAnchor(playerAnchor), ((CraftEntity) entity).getHandle(), toNmsAnchor(entityAnchor)); ++ } ++ ++ @Override ++ public void lookAt(double x, double y, double z, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor) { ++ this.getHandle().lookAt(toNmsAnchor(playerAnchor), new net.minecraft.world.phys.Vec3(x, y, z)); ++ } ++ ++ public static net.minecraft.commands.arguments.EntityAnchorArgument.Anchor toNmsAnchor(io.papermc.paper.entity.LookAnchor nmsAnchor) { ++ return switch (nmsAnchor) { ++ case EYES -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.EYES; ++ case FEET -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.FEET; ++ }; ++ } ++ ++ public static io.papermc.paper.entity.LookAnchor toApiAnchor(net.minecraft.commands.arguments.EntityAnchorArgument.Anchor playerAnchor) { ++ return switch (playerAnchor) { ++ case EYES -> io.papermc.paper.entity.LookAnchor.EYES; ++ case FEET -> io.papermc.paper.entity.LookAnchor.FEET; ++ }; ++ } ++ ++ public static net.minecraft.world.entity.Relative toNmsRelativeFlag(io.papermc.paper.entity.TeleportFlag.Relative apiFlag) { ++ return switch (apiFlag) { ++ case X -> net.minecraft.world.entity.Relative.X; ++ case Y -> net.minecraft.world.entity.Relative.Y; ++ case Z -> net.minecraft.world.entity.Relative.Z; ++ case PITCH -> net.minecraft.world.entity.Relative.X_ROT; ++ case YAW -> net.minecraft.world.entity.Relative.Y_ROT; ++ }; ++ } ++ ++ public static io.papermc.paper.entity.TeleportFlag.Relative toApiRelativeFlag(net.minecraft.world.entity.Relative nmsFlag) { ++ return switch (nmsFlag) { ++ case X -> io.papermc.paper.entity.TeleportFlag.Relative.X; ++ case Y -> io.papermc.paper.entity.TeleportFlag.Relative.Y; ++ case Z -> io.papermc.paper.entity.TeleportFlag.Relative.Z; ++ case X_ROT -> io.papermc.paper.entity.TeleportFlag.Relative.PITCH; ++ case Y_ROT -> io.papermc.paper.entity.TeleportFlag.Relative.YAW; ++ default -> throw new RuntimeException("not yet"); // TODO figure out what to do with new flags ++ }; ++ } ++ ++ @Override ++ public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { ++ Set relativeArguments; ++ Set allFlags; ++ if (flags.length == 0) { ++ relativeArguments = Set.of(); ++ allFlags = Set.of(); ++ } else { ++ relativeArguments = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class); ++ allFlags = new HashSet<>(); ++ for (io.papermc.paper.entity.TeleportFlag flag : flags) { ++ if (flag instanceof final io.papermc.paper.entity.TeleportFlag.Relative relativeTeleportFlag) { ++ relativeArguments.add(relativeTeleportFlag); ++ } ++ allFlags.add(flag); ++ } ++ } ++ boolean dismount = !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE); ++ boolean ignorePassengers = allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS); ++ // Paper end - Teleport API + Preconditions.checkArgument(location != null, "location"); + Preconditions.checkArgument(location.getWorld() != null, "location.world"); ++ // Paper start - Teleport passenger API ++ // Don't allow teleporting between worlds while keeping passengers ++ if (ignorePassengers && entity.isVehicle() && location.getWorld() != this.getWorld()) { ++ return false; ++ } ++ ++ // Don't allow to teleport between worlds if remaining on vehicle ++ if (!dismount && entity.isPassenger() && location.getWorld() != this.getWorld()) { ++ return false; ++ } ++ // Paper end + location.checkFinite(); + + ServerPlayer entity = this.getHandle(); +@@ -1322,7 +1411,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + return false; + } + +- if (entity.isVehicle()) { ++ if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API + return false; + } + +@@ -1331,7 +1420,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + // To = Players new Location if Teleport is Successful + Location to = location; + // Create & Call the Teleport Event. +- PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause); ++ PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause, Set.copyOf(relativeArguments)); // Paper - Teleport API + this.server.getPluginManager().callEvent(event); + + // Return False to inform the Plugin that the Teleport was unsuccessful/cancelled. +@@ -1340,7 +1429,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + + // If this player is riding another entity, we must dismount before teleporting. +- entity.stopRiding(); ++ if (dismount) entity.stopRiding(); // Paper - Teleport API + + // SPIGOT-5509: Wakeup, similar to riding + if (this.isSleeping()) { +@@ -1356,13 +1445,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + ServerLevel toWorld = ((CraftWorld) to.getWorld()).getHandle(); + + // Close any foreign inventory +- if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) { ++ if (this.getHandle().containerMenu != this.getHandle().inventoryMenu && !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_OPEN_INVENTORY)) { // Paper + this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); // Paper - Inventory close reason + } + + // Check if the fromWorld and toWorld are the same. + if (fromWorld == toWorld) { +- entity.connection.teleport(to); ++ // Paper start - Teleport API ++ final Set nms = java.util.EnumSet.noneOf(net.minecraft.world.entity.Relative.class); ++ for (final io.papermc.paper.entity.TeleportFlag.Relative bukkit : relativeArguments) { ++ nms.add(toNmsRelativeFlag(bukkit)); ++ } ++ entity.connection.internalTeleport(new net.minecraft.world.entity.PositionMoveRotation( ++ io.papermc.paper.util.MCUtil.toVec3(to), net.minecraft.world.phys.Vec3.ZERO, to.getYaw(), to.getPitch() ++ ), nms); ++ // Paper end - Teleport API + } else { + entity.portalProcess = null; // SPIGOT-7785: there is no need to carry this over as it contains the old world/location and we might run into trouble if there is a portal in the same spot in both worlds + // The respawn reason should never be used if the passed location is non null. diff --git a/patches/server/0716-Add-EntityPortalReadyEvent.patch b/patches/server/0716-Add-EntityPortalReadyEvent.patch new file mode 100644 index 0000000000..46f19b8cc8 --- /dev/null +++ b/patches/server/0716-Add-EntityPortalReadyEvent.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 12 May 2021 04:30:42 -0700 +Subject: [PATCH] Add EntityPortalReadyEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +index c00507fa7af579263caed67dafc2ea9eba09512b..fb361eac03c16ecee02219ff0524cce2292c7976 100644 +--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -141,6 +141,14 @@ public class NetherPortalBlock extends Block implements Portal { + // CraftBukkit start + ResourceKey resourcekey = world.getTypeKey() == LevelStem.NETHER ? Level.OVERWORLD : Level.NETHER; + ServerLevel worldserver1 = world.getServer().getLevel(resourcekey); ++ // Paper start - Add EntityPortalReadyEvent ++ io.papermc.paper.event.entity.EntityPortalReadyEvent portalReadyEvent = new io.papermc.paper.event.entity.EntityPortalReadyEvent(entity.getBukkitEntity(), worldserver1 == null ? null : worldserver1.getWorld(), org.bukkit.PortalType.NETHER); ++ if (!portalReadyEvent.callEvent()) { ++ entity.portalProcess = null; ++ return null; ++ } ++ worldserver1 = portalReadyEvent.getTargetWorld() == null ? null : ((org.bukkit.craftbukkit.CraftWorld) portalReadyEvent.getTargetWorld()).getHandle(); ++ // Paper end - Add EntityPortalReadyEvent + + if (worldserver1 == null) { + return new TeleportTransition(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // always fire event in case plugins wish to change it diff --git a/patches/server/0716-More-Teleport-API.patch b/patches/server/0716-More-Teleport-API.patch deleted file mode 100644 index c2d39bdc63..0000000000 --- a/patches/server/0716-More-Teleport-API.patch +++ /dev/null @@ -1,272 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 5 Sep 2021 12:15:59 -0400 -Subject: [PATCH] More Teleport API - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index ac2ad33a44ce04d9673adc08ff21a167d606e4db..349da8b85b7a122977fcad80a399605109b88db2 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1585,11 +1585,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - return true; // CraftBukkit - Return event status - } - -- PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause); -+ // Paper start - Teleport API -+ Set relativeFlags = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class); -+ for (Relative relativeArgument : set) { -+ relativeFlags.add(org.bukkit.craftbukkit.entity.CraftPlayer.toApiRelativeFlag(relativeArgument)); -+ } -+ PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause, java.util.Set.copyOf(relativeFlags)); -+ // Paper end - Teleport API - this.cserver.getPluginManager().callEvent(event); - - if (event.isCancelled() || !to.equals(event.getTo())) { -- set = Collections.emptySet(); // Can't relative teleport -+ // set = Collections.emptySet(); // Can't relative teleport // Paper - Teleport API; Now you can! - to = event.isCancelled() ? event.getFrom() : event.getTo(); - positionmoverotation = new PositionMoveRotation(CraftLocation.toVec3D(to), Vec3.ZERO, to.getYaw(), to.getPitch()); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 4e6afa243d6108cb946a8a7cf96c4036a3c2ac0c..a314e401ee8a306dc12a2d98a3d400ae611a6e5a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -222,15 +222,36 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - - @Override - public boolean teleport(Location location, TeleportCause cause) { -+ // Paper start - Teleport passenger API -+ return teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]); -+ } -+ -+ @Override -+ public boolean teleport(Location location, TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { -+ // Paper end - Preconditions.checkArgument(location != null, "location cannot be null"); - location.checkFinite(); -+ // Paper start - Teleport passenger API -+ Set flagSet = Set.of(flags); -+ boolean dismount = !flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE); -+ boolean ignorePassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS); -+ // Don't allow teleporting between worlds while keeping passengers -+ if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) { -+ return false; -+ } -+ -+ // Don't allow to teleport between worlds if remaining on vehicle -+ if (!dismount && this.entity.isPassenger() && location.getWorld() != this.getWorld()) { -+ return false; -+ } -+ // Paper end - -- if (this.entity.isVehicle() || this.entity.isRemoved()) { -+ if ((!ignorePassengers && this.entity.isVehicle()) || this.entity.isRemoved()) { // Paper - Teleport passenger API - return false; - } - - // If this entity is riding another entity, we must dismount before teleporting. -- this.entity.stopRiding(); -+ if (dismount) this.entity.stopRiding(); // Paper - Teleport passenger API - - // Let the server handle cross world teleports - if (location.getWorld() != null && !location.getWorld().equals(this.getWorld())) { -@@ -976,6 +997,39 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return CraftEntity.perm; - } - -+ // Paper start - more teleport API / async chunk API -+ @Override -+ public java.util.concurrent.CompletableFuture teleportAsync(final Location location, final TeleportCause cause, final io.papermc.paper.entity.TeleportFlag... teleportFlags) { -+ Preconditions.checkArgument(location != null, "location"); -+ location.checkFinite(); -+ Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. -+ -+ net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle(); -+ java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); -+ -+ world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), -+ this instanceof CraftPlayer ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, (list) -> { -+ net.minecraft.server.level.ServerChunkCache chunkProviderServer = world.getChunkSource(); -+ for (net.minecraft.world.level.chunk.ChunkAccess chunk : list) { -+ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); -+ } -+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { -+ try { -+ ret.complete(CraftEntity.this.teleport(locationClone, cause, teleportFlags) ? Boolean.TRUE : Boolean.FALSE); -+ } catch (Throwable throwable) { -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } -+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to teleport entity " + CraftEntity.this, throwable); -+ ret.completeExceptionally(throwable); -+ } -+ }); -+ }); -+ -+ return ret; -+ } -+ // Paper end - more teleport API / async chunk API -+ - // Spigot start - private final org.bukkit.entity.Entity.Spigot spigot = new org.bukkit.entity.Entity.Spigot() - { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index fe0c355f8203c9bfa30d2ec48392a5a1a3d616ae..baae7a129853a296273b7f295f58cbb99187da22 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1303,13 +1303,102 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void setRotation(float yaw, float pitch) { -- throw new UnsupportedOperationException("Cannot set rotation of players. Consider teleporting instead."); -+ // Paper start - Teleport API -+ Location targetLocation = this.getEyeLocation(); -+ targetLocation.setYaw(yaw); -+ targetLocation.setPitch(pitch); -+ -+ org.bukkit.util.Vector direction = targetLocation.getDirection(); -+ direction.multiply(9999999); // We need to move the target block.. FAR out -+ targetLocation.add(direction); -+ this.lookAt(targetLocation, io.papermc.paper.entity.LookAnchor.EYES); -+ // Paper end - } - - @Override - public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) { -+ // Paper start - Teleport API -+ return this.teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]); -+ } -+ -+ @Override -+ public void lookAt(@NotNull org.bukkit.entity.Entity entity, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor, @NotNull io.papermc.paper.entity.LookAnchor entityAnchor) { -+ this.getHandle().lookAt(toNmsAnchor(playerAnchor), ((CraftEntity) entity).getHandle(), toNmsAnchor(entityAnchor)); -+ } -+ -+ @Override -+ public void lookAt(double x, double y, double z, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor) { -+ this.getHandle().lookAt(toNmsAnchor(playerAnchor), new net.minecraft.world.phys.Vec3(x, y, z)); -+ } -+ -+ public static net.minecraft.commands.arguments.EntityAnchorArgument.Anchor toNmsAnchor(io.papermc.paper.entity.LookAnchor nmsAnchor) { -+ return switch (nmsAnchor) { -+ case EYES -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.EYES; -+ case FEET -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.FEET; -+ }; -+ } -+ -+ public static io.papermc.paper.entity.LookAnchor toApiAnchor(net.minecraft.commands.arguments.EntityAnchorArgument.Anchor playerAnchor) { -+ return switch (playerAnchor) { -+ case EYES -> io.papermc.paper.entity.LookAnchor.EYES; -+ case FEET -> io.papermc.paper.entity.LookAnchor.FEET; -+ }; -+ } -+ -+ public static net.minecraft.world.entity.Relative toNmsRelativeFlag(io.papermc.paper.entity.TeleportFlag.Relative apiFlag) { -+ return switch (apiFlag) { -+ case X -> net.minecraft.world.entity.Relative.X; -+ case Y -> net.minecraft.world.entity.Relative.Y; -+ case Z -> net.minecraft.world.entity.Relative.Z; -+ case PITCH -> net.minecraft.world.entity.Relative.X_ROT; -+ case YAW -> net.minecraft.world.entity.Relative.Y_ROT; -+ }; -+ } -+ -+ public static io.papermc.paper.entity.TeleportFlag.Relative toApiRelativeFlag(net.minecraft.world.entity.Relative nmsFlag) { -+ return switch (nmsFlag) { -+ case X -> io.papermc.paper.entity.TeleportFlag.Relative.X; -+ case Y -> io.papermc.paper.entity.TeleportFlag.Relative.Y; -+ case Z -> io.papermc.paper.entity.TeleportFlag.Relative.Z; -+ case X_ROT -> io.papermc.paper.entity.TeleportFlag.Relative.PITCH; -+ case Y_ROT -> io.papermc.paper.entity.TeleportFlag.Relative.YAW; -+ default -> throw new RuntimeException("not yet"); // TODO figure out what to do with new flags -+ }; -+ } -+ -+ @Override -+ public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { -+ Set relativeArguments; -+ Set allFlags; -+ if (flags.length == 0) { -+ relativeArguments = Set.of(); -+ allFlags = Set.of(); -+ } else { -+ relativeArguments = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class); -+ allFlags = new HashSet<>(); -+ for (io.papermc.paper.entity.TeleportFlag flag : flags) { -+ if (flag instanceof final io.papermc.paper.entity.TeleportFlag.Relative relativeTeleportFlag) { -+ relativeArguments.add(relativeTeleportFlag); -+ } -+ allFlags.add(flag); -+ } -+ } -+ boolean dismount = !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE); -+ boolean ignorePassengers = allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS); -+ // Paper end - Teleport API - Preconditions.checkArgument(location != null, "location"); - Preconditions.checkArgument(location.getWorld() != null, "location.world"); -+ // Paper start - Teleport passenger API -+ // Don't allow teleporting between worlds while keeping passengers -+ if (ignorePassengers && entity.isVehicle() && location.getWorld() != this.getWorld()) { -+ return false; -+ } -+ -+ // Don't allow to teleport between worlds if remaining on vehicle -+ if (!dismount && entity.isPassenger() && location.getWorld() != this.getWorld()) { -+ return false; -+ } -+ // Paper end - location.checkFinite(); - - ServerPlayer entity = this.getHandle(); -@@ -1322,7 +1411,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - return false; - } - -- if (entity.isVehicle()) { -+ if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API - return false; - } - -@@ -1331,7 +1420,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - // To = Players new Location if Teleport is Successful - Location to = location; - // Create & Call the Teleport Event. -- PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause); -+ PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause, Set.copyOf(relativeArguments)); // Paper - Teleport API - this.server.getPluginManager().callEvent(event); - - // Return False to inform the Plugin that the Teleport was unsuccessful/cancelled. -@@ -1340,7 +1429,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - - // If this player is riding another entity, we must dismount before teleporting. -- entity.stopRiding(); -+ if (dismount) entity.stopRiding(); // Paper - Teleport API - - // SPIGOT-5509: Wakeup, similar to riding - if (this.isSleeping()) { -@@ -1356,13 +1445,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - ServerLevel toWorld = ((CraftWorld) to.getWorld()).getHandle(); - - // Close any foreign inventory -- if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) { -+ if (this.getHandle().containerMenu != this.getHandle().inventoryMenu && !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_OPEN_INVENTORY)) { // Paper - this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); // Paper - Inventory close reason - } - - // Check if the fromWorld and toWorld are the same. - if (fromWorld == toWorld) { -- entity.connection.teleport(to); -+ // Paper start - Teleport API -+ final Set nms = java.util.EnumSet.noneOf(net.minecraft.world.entity.Relative.class); -+ for (final io.papermc.paper.entity.TeleportFlag.Relative bukkit : relativeArguments) { -+ nms.add(toNmsRelativeFlag(bukkit)); -+ } -+ entity.connection.internalTeleport(new net.minecraft.world.entity.PositionMoveRotation( -+ io.papermc.paper.util.MCUtil.toVec3(to), net.minecraft.world.phys.Vec3.ZERO, to.getYaw(), to.getPitch() -+ ), nms); -+ // Paper end - Teleport API - } else { - entity.portalProcess = null; // SPIGOT-7785: there is no need to carry this over as it contains the old world/location and we might run into trouble if there is a portal in the same spot in both worlds - // The respawn reason should never be used if the passed location is non null. diff --git a/patches/server/0717-Add-EntityPortalReadyEvent.patch b/patches/server/0717-Add-EntityPortalReadyEvent.patch deleted file mode 100644 index 46f19b8cc8..0000000000 --- a/patches/server/0717-Add-EntityPortalReadyEvent.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 12 May 2021 04:30:42 -0700 -Subject: [PATCH] Add EntityPortalReadyEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -index c00507fa7af579263caed67dafc2ea9eba09512b..fb361eac03c16ecee02219ff0524cce2292c7976 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -@@ -141,6 +141,14 @@ public class NetherPortalBlock extends Block implements Portal { - // CraftBukkit start - ResourceKey resourcekey = world.getTypeKey() == LevelStem.NETHER ? Level.OVERWORLD : Level.NETHER; - ServerLevel worldserver1 = world.getServer().getLevel(resourcekey); -+ // Paper start - Add EntityPortalReadyEvent -+ io.papermc.paper.event.entity.EntityPortalReadyEvent portalReadyEvent = new io.papermc.paper.event.entity.EntityPortalReadyEvent(entity.getBukkitEntity(), worldserver1 == null ? null : worldserver1.getWorld(), org.bukkit.PortalType.NETHER); -+ if (!portalReadyEvent.callEvent()) { -+ entity.portalProcess = null; -+ return null; -+ } -+ worldserver1 = portalReadyEvent.getTargetWorld() == null ? null : ((org.bukkit.craftbukkit.CraftWorld) portalReadyEvent.getTargetWorld()).getHandle(); -+ // Paper end - Add EntityPortalReadyEvent - - if (worldserver1 == null) { - return new TeleportTransition(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // always fire event in case plugins wish to change it diff --git a/patches/server/0717-Don-t-use-level-random-in-entity-constructors.patch b/patches/server/0717-Don-t-use-level-random-in-entity-constructors.patch new file mode 100644 index 0000000000..9ec489bd3e --- /dev/null +++ b/patches/server/0717-Don-t-use-level-random-in-entity-constructors.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 10 Jul 2022 14:13:22 -0700 +Subject: [PATCH] Don't use level random in entity constructors + +Paper makes the entity random thread-safe +and constructing an entity off the main thread +should be supported. Some entities (for whatever +reason) use the level's random in some places. + +diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +index 6b19689a19465554b943470fc6f959e48169ac5b..aa41c4cf8d3ae291c4147118c96190ff0bb807b2 100644 +--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java ++++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +@@ -72,7 +72,12 @@ public class ItemEntity extends Entity implements TraceableEntity { + } + + public ItemEntity(Level world, double x, double y, double z, ItemStack stack) { +- this(world, x, y, z, stack, world.random.nextDouble() * 0.2D - 0.1D, 0.2D, world.random.nextDouble() * 0.2D - 0.1D); ++ // Paper start - Don't use level random in entity constructors (to make them thread-safe) ++ this(EntityType.ITEM, world); ++ this.setPos(x, y, z); ++ this.setDeltaMovement(this.random.nextDouble() * 0.2D - 0.1D, 0.2D, this.random.nextDouble() * 0.2D - 0.1D); ++ this.setItem(stack); ++ // Paper end - Don't use level random in entity constructors + } + + public ItemEntity(Level world, double x, double y, double z, ItemStack stack, double velocityX, double velocityY, double velocityZ) { +diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +index 45c224198135e48f94dc72312c805bf451bf7b0e..de87483600e55d88176fe25db621bbd3e464729f 100644 +--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java ++++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +@@ -68,7 +68,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { + public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) { + this(EntityType.TNT, world); + this.setPos(x, y, z); +- double d3 = world.random.nextDouble() * 6.2831854820251465D; ++ double d3 = this.random.nextDouble() * 6.2831854820251465D; // Paper - Don't use level random in entity constructors + + this.setDeltaMovement(-Math.sin(d3) * 0.02D, 0.20000000298023224D, -Math.cos(d3) * 0.02D); + this.setFuse(80); diff --git a/patches/server/0718-Don-t-use-level-random-in-entity-constructors.patch b/patches/server/0718-Don-t-use-level-random-in-entity-constructors.patch deleted file mode 100644 index 9ec489bd3e..0000000000 --- a/patches/server/0718-Don-t-use-level-random-in-entity-constructors.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 10 Jul 2022 14:13:22 -0700 -Subject: [PATCH] Don't use level random in entity constructors - -Paper makes the entity random thread-safe -and constructing an entity off the main thread -should be supported. Some entities (for whatever -reason) use the level's random in some places. - -diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -index 6b19689a19465554b943470fc6f959e48169ac5b..aa41c4cf8d3ae291c4147118c96190ff0bb807b2 100644 ---- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -@@ -72,7 +72,12 @@ public class ItemEntity extends Entity implements TraceableEntity { - } - - public ItemEntity(Level world, double x, double y, double z, ItemStack stack) { -- this(world, x, y, z, stack, world.random.nextDouble() * 0.2D - 0.1D, 0.2D, world.random.nextDouble() * 0.2D - 0.1D); -+ // Paper start - Don't use level random in entity constructors (to make them thread-safe) -+ this(EntityType.ITEM, world); -+ this.setPos(x, y, z); -+ this.setDeltaMovement(this.random.nextDouble() * 0.2D - 0.1D, 0.2D, this.random.nextDouble() * 0.2D - 0.1D); -+ this.setItem(stack); -+ // Paper end - Don't use level random in entity constructors - } - - public ItemEntity(Level world, double x, double y, double z, ItemStack stack, double velocityX, double velocityY, double velocityZ) { -diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 45c224198135e48f94dc72312c805bf451bf7b0e..de87483600e55d88176fe25db621bbd3e464729f 100644 ---- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -68,7 +68,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { - public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) { - this(EntityType.TNT, world); - this.setPos(x, y, z); -- double d3 = world.random.nextDouble() * 6.2831854820251465D; -+ double d3 = this.random.nextDouble() * 6.2831854820251465D; // Paper - Don't use level random in entity constructors - - this.setDeltaMovement(-Math.sin(d3) * 0.02D, 0.20000000298023224D, -Math.cos(d3) * 0.02D); - this.setFuse(80); diff --git a/patches/server/0718-Send-block-entities-after-destroy-prediction.patch b/patches/server/0718-Send-block-entities-after-destroy-prediction.patch new file mode 100644 index 0000000000..6fcd859761 --- /dev/null +++ b/patches/server/0718-Send-block-entities-after-destroy-prediction.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sat, 25 Jun 2022 19:45:20 -0400 +Subject: [PATCH] Send block entities after destroy prediction + +Minecraft's prediction system does not handle block entities, so if we are manually sending block entities during +block breaking we need to set it after the prediction is finished. This fixes block entities not showing when cancelling the BlockBreakEvent. + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 5c3e5c348e6fececccd8097355f423b9e7ad982b..064a7a3e1c4d192010e072a5e985a54135748d87 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -61,6 +61,8 @@ public class ServerPlayerGameMode { + private BlockPos delayedDestroyPos; + private int delayedTickStart; + private int lastSentState; ++ public boolean captureSentBlockEntities = false; // Paper - Send block entities after destroy prediction ++ public boolean capturedBlockEntity = false; // Paper - Send block entities after destroy prediction + + public ServerPlayerGameMode(ServerPlayer player) { + this.gameModeForPlayer = GameType.DEFAULT_MODE; +@@ -191,10 +193,7 @@ public class ServerPlayerGameMode { + this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos))); + this.debugLogging(pos, false, sequence, "may not interact"); + // Update any tile entity data for this block +- BlockEntity tileentity = this.level.getBlockEntity(pos); +- if (tileentity != null) { +- this.player.connection.send(tileentity.getUpdatePacket()); +- } ++ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction + // CraftBukkit end + return; + } +@@ -205,10 +204,7 @@ public class ServerPlayerGameMode { + // Let the client know the block still exists + this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); + // Update any tile entity data for this block +- BlockEntity tileentity = this.level.getBlockEntity(pos); +- if (tileentity != null) { +- this.player.connection.send(tileentity.getUpdatePacket()); +- } ++ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction + return; + } + // CraftBukkit end +@@ -393,10 +389,12 @@ public class ServerPlayerGameMode { + } + + // Update any tile entity data for this block ++ if (!captureSentBlockEntities) { // Paper - Send block entities after destroy prediction + BlockEntity tileentity = this.level.getBlockEntity(pos); + if (tileentity != null) { + this.player.connection.send(tileentity.getUpdatePacket()); + } ++ } else {capturedBlockEntity = true;} // Paper - Send block entities after destroy prediction + return false; + } + } +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 4d64eedfbe5b967572b7140ddfb55efa1ccc3650..b48966424fb8e937552c0e7bffaedaefc63ef77f 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1723,8 +1723,28 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + return; + } + // Paper end - Don't allow digging into unloaded chunks ++ // Paper start - Send block entities after destroy prediction ++ this.player.gameMode.capturedBlockEntity = false; ++ this.player.gameMode.captureSentBlockEntities = true; ++ // Paper end - Send block entities after destroy prediction + this.player.gameMode.handleBlockBreakAction(blockposition, packetplayinblockdig_enumplayerdigtype, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence()); + this.player.connection.ackBlockChangesUpTo(packet.getSequence()); ++ // Paper start - Send block entities after destroy prediction ++ this.player.gameMode.captureSentBlockEntities = false; ++ // If a block entity was modified speedup the block change ack to avoid the block entity ++ // being overriden. ++ if (this.player.gameMode.capturedBlockEntity) { ++ // manually tick ++ this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); ++ this.player.connection.ackBlockChangesUpTo = -1; ++ ++ this.player.gameMode.capturedBlockEntity = false; ++ BlockEntity tileentity = this.player.level().getBlockEntity(blockposition); ++ if (tileentity != null) { ++ this.player.connection.send(tileentity.getUpdatePacket()); ++ } ++ } ++ // Paper end - Send block entities after destroy prediction + return; + default: + throw new IllegalArgumentException("Invalid player action"); diff --git a/patches/server/0719-Send-block-entities-after-destroy-prediction.patch b/patches/server/0719-Send-block-entities-after-destroy-prediction.patch deleted file mode 100644 index 2742769b83..0000000000 --- a/patches/server/0719-Send-block-entities-after-destroy-prediction.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sat, 25 Jun 2022 19:45:20 -0400 -Subject: [PATCH] Send block entities after destroy prediction - -Minecraft's prediction system does not handle block entities, so if we are manually sending block entities during -block breaking we need to set it after the prediction is finished. This fixes block entities not showing when cancelling the BlockBreakEvent. - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 5c3e5c348e6fececccd8097355f423b9e7ad982b..064a7a3e1c4d192010e072a5e985a54135748d87 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -61,6 +61,8 @@ public class ServerPlayerGameMode { - private BlockPos delayedDestroyPos; - private int delayedTickStart; - private int lastSentState; -+ public boolean captureSentBlockEntities = false; // Paper - Send block entities after destroy prediction -+ public boolean capturedBlockEntity = false; // Paper - Send block entities after destroy prediction - - public ServerPlayerGameMode(ServerPlayer player) { - this.gameModeForPlayer = GameType.DEFAULT_MODE; -@@ -191,10 +193,7 @@ public class ServerPlayerGameMode { - this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos))); - this.debugLogging(pos, false, sequence, "may not interact"); - // Update any tile entity data for this block -- BlockEntity tileentity = this.level.getBlockEntity(pos); -- if (tileentity != null) { -- this.player.connection.send(tileentity.getUpdatePacket()); -- } -+ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction - // CraftBukkit end - return; - } -@@ -205,10 +204,7 @@ public class ServerPlayerGameMode { - // Let the client know the block still exists - this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); - // Update any tile entity data for this block -- BlockEntity tileentity = this.level.getBlockEntity(pos); -- if (tileentity != null) { -- this.player.connection.send(tileentity.getUpdatePacket()); -- } -+ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction - return; - } - // CraftBukkit end -@@ -393,10 +389,12 @@ public class ServerPlayerGameMode { - } - - // Update any tile entity data for this block -+ if (!captureSentBlockEntities) { // Paper - Send block entities after destroy prediction - BlockEntity tileentity = this.level.getBlockEntity(pos); - if (tileentity != null) { - this.player.connection.send(tileentity.getUpdatePacket()); - } -+ } else {capturedBlockEntity = true;} // Paper - Send block entities after destroy prediction - return false; - } - } -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 349da8b85b7a122977fcad80a399605109b88db2..32ed76fca856b7d121e2215748be4f6d1b18791a 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1723,8 +1723,28 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - return; - } - // Paper end - Don't allow digging into unloaded chunks -+ // Paper start - Send block entities after destroy prediction -+ this.player.gameMode.capturedBlockEntity = false; -+ this.player.gameMode.captureSentBlockEntities = true; -+ // Paper end - Send block entities after destroy prediction - this.player.gameMode.handleBlockBreakAction(blockposition, packetplayinblockdig_enumplayerdigtype, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence()); - this.player.connection.ackBlockChangesUpTo(packet.getSequence()); -+ // Paper start - Send block entities after destroy prediction -+ this.player.gameMode.captureSentBlockEntities = false; -+ // If a block entity was modified speedup the block change ack to avoid the block entity -+ // being overriden. -+ if (this.player.gameMode.capturedBlockEntity) { -+ // manually tick -+ this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); -+ this.player.connection.ackBlockChangesUpTo = -1; -+ -+ this.player.gameMode.capturedBlockEntity = false; -+ BlockEntity tileentity = this.player.level().getBlockEntity(blockposition); -+ if (tileentity != null) { -+ this.player.connection.send(tileentity.getUpdatePacket()); -+ } -+ } -+ // Paper end - Send block entities after destroy prediction - return; - default: - throw new IllegalArgumentException("Invalid player action"); diff --git a/patches/server/0719-Warn-on-plugins-accessing-faraway-chunks.patch b/patches/server/0719-Warn-on-plugins-accessing-faraway-chunks.patch new file mode 100644 index 0000000000..2b2ca909d0 --- /dev/null +++ b/patches/server/0719-Warn-on-plugins-accessing-faraway-chunks.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Fri, 29 Jul 2022 12:35:19 -0400 +Subject: [PATCH] Warn on plugins accessing faraway chunks + + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 9afc0eaaca5ab7b6445d90ce53e31a6ae76f8848..f0c2187a92de633a1d4cc7e71ff62cbe30ce8774 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -337,7 +337,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + } + + private static boolean isInWorldBoundsHorizontal(BlockPos pos) { +- return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; ++ return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; // Diff on change warnUnsafeChunk() + } + + private static boolean isOutsideSpawnableHeight(int y) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 9240460b9ec582ac01d3074c9bc923191bf0ad95..c0f5e4497e1ffc93f56fc2b5748bcf76569e8c3a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -309,9 +309,24 @@ public class CraftWorld extends CraftRegionAccessor implements World { + public boolean setSpawnLocation(int x, int y, int z) { + return this.setSpawnLocation(x, y, z, 0.0F); + } ++ // Paper start ++ private static void warnUnsafeChunk(String reason, int x, int z) { ++ // if any chunk coord is outside of 30 million blocks ++ if (x > 1875000 || z > 1875000 || x < -1875000 || z < -1875000) { ++ Plugin plugin = io.papermc.paper.util.StackWalkerUtil.getFirstPluginCaller(); ++ if (plugin != null) { ++ plugin.getLogger().warning("Plugin is %s at (%s, %s), this might cause issues.".formatted(reason, x, z)); ++ } ++ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) { ++ io.papermc.paper.util.TraceUtil.dumpTraceForThread("Dangerous chunk retrieval"); ++ } ++ } ++ } ++ // Paper end + + @Override + public Chunk getChunkAt(int x, int z) { ++ warnUnsafeChunk("getting a faraway chunk", x, z); // Paper + // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it + net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); + if (chunk == null) { +@@ -419,6 +434,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + if (!unloadChunk0(x, z, false)) { + return false; + } ++ warnUnsafeChunk("regenerating a faraway chunk", x, z); // Paper + + final long chunkKey = ChunkCoordIntPair.pair(x, z); + world.getChunkProvider().unloadQueue.remove(chunkKey); +@@ -492,6 +508,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + public boolean loadChunk(int x, int z, boolean generate) { + org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot ++ warnUnsafeChunk("loading a faraway chunk", x, z); // Paper + ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper + + // If generate = false, but the chunk already exists, we will get this back. +@@ -524,6 +541,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean addPluginChunkTicket(int x, int z, Plugin plugin) { ++ warnUnsafeChunk("adding a faraway chunk ticket", x, z); // Paper + Preconditions.checkArgument(plugin != null, "null plugin"); + Preconditions.checkArgument(plugin.isEnabled(), "plugin is not enabled"); + +@@ -624,6 +642,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setChunkForceLoaded(int x, int z, boolean forced) { ++ warnUnsafeChunk("forceloading a faraway chunk", x, z); // Paper + this.getHandle().setChunkForced(x, z, forced); + } + +@@ -958,6 +977,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) { ++ warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper + // Transient load for this tick + return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z); + } +@@ -2358,6 +2378,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + // Spigot end + // Paper start + public java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { ++ warnUnsafeChunk("getting a faraway chunk async", x, z); // Paper + if (Bukkit.isPrimaryThread()) { + net.minecraft.world.level.chunk.LevelChunk immediate = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); + if (immediate != null) { diff --git a/patches/server/0720-Custom-Chat-Completion-Suggestions-API.patch b/patches/server/0720-Custom-Chat-Completion-Suggestions-API.patch new file mode 100644 index 0000000000..9908dc279c --- /dev/null +++ b/patches/server/0720-Custom-Chat-Completion-Suggestions-API.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sat, 30 Jul 2022 11:23:05 -0400 +Subject: [PATCH] Custom Chat Completion Suggestions API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index baae7a129853a296273b7f295f58cbb99187da22..58f3ca95b1d79269bed3b6473cd69d8988ede162 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -708,6 +708,24 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + // Paper end - Add sendOpLevel API + ++ // Paper start - custom chat completions API ++ @Override ++ public void addAdditionalChatCompletions(@NotNull Collection completions) { ++ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket( ++ net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket.Action.ADD, ++ new ArrayList<>(completions) ++ )); ++ } ++ ++ @Override ++ public void removeAdditionalChatCompletions(@NotNull Collection completions) { ++ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket( ++ net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket.Action.REMOVE, ++ new ArrayList<>(completions) ++ )); ++ } ++ // Paper end - custom chat completions API ++ + @Override + public void setCompassTarget(Location loc) { + Preconditions.checkArgument(loc != null, "Location cannot be null"); diff --git a/patches/server/0720-Warn-on-plugins-accessing-faraway-chunks.patch b/patches/server/0720-Warn-on-plugins-accessing-faraway-chunks.patch deleted file mode 100644 index c1e4213d1c..0000000000 --- a/patches/server/0720-Warn-on-plugins-accessing-faraway-chunks.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Fri, 29 Jul 2022 12:35:19 -0400 -Subject: [PATCH] Warn on plugins accessing faraway chunks - - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 8269bf24f5e17f9e3936659aa0cbc9d4f95fb665..a6f538372830f3f80740ef503733736e0561d1bd 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -339,7 +339,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - - private static boolean isInWorldBoundsHorizontal(BlockPos pos) { -- return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; -+ return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; // Diff on change warnUnsafeChunk() - } - - private static boolean isOutsideSpawnableHeight(int y) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 9240460b9ec582ac01d3074c9bc923191bf0ad95..c0f5e4497e1ffc93f56fc2b5748bcf76569e8c3a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -309,9 +309,24 @@ public class CraftWorld extends CraftRegionAccessor implements World { - public boolean setSpawnLocation(int x, int y, int z) { - return this.setSpawnLocation(x, y, z, 0.0F); - } -+ // Paper start -+ private static void warnUnsafeChunk(String reason, int x, int z) { -+ // if any chunk coord is outside of 30 million blocks -+ if (x > 1875000 || z > 1875000 || x < -1875000 || z < -1875000) { -+ Plugin plugin = io.papermc.paper.util.StackWalkerUtil.getFirstPluginCaller(); -+ if (plugin != null) { -+ plugin.getLogger().warning("Plugin is %s at (%s, %s), this might cause issues.".formatted(reason, x, z)); -+ } -+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) { -+ io.papermc.paper.util.TraceUtil.dumpTraceForThread("Dangerous chunk retrieval"); -+ } -+ } -+ } -+ // Paper end - - @Override - public Chunk getChunkAt(int x, int z) { -+ warnUnsafeChunk("getting a faraway chunk", x, z); // Paper - // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it - net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); - if (chunk == null) { -@@ -419,6 +434,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - if (!unloadChunk0(x, z, false)) { - return false; - } -+ warnUnsafeChunk("regenerating a faraway chunk", x, z); // Paper - - final long chunkKey = ChunkCoordIntPair.pair(x, z); - world.getChunkProvider().unloadQueue.remove(chunkKey); -@@ -492,6 +508,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - public boolean loadChunk(int x, int z, boolean generate) { - org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot -+ warnUnsafeChunk("loading a faraway chunk", x, z); // Paper - ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper - - // If generate = false, but the chunk already exists, we will get this back. -@@ -524,6 +541,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean addPluginChunkTicket(int x, int z, Plugin plugin) { -+ warnUnsafeChunk("adding a faraway chunk ticket", x, z); // Paper - Preconditions.checkArgument(plugin != null, "null plugin"); - Preconditions.checkArgument(plugin.isEnabled(), "plugin is not enabled"); - -@@ -624,6 +642,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setChunkForceLoaded(int x, int z, boolean forced) { -+ warnUnsafeChunk("forceloading a faraway chunk", x, z); // Paper - this.getHandle().setChunkForced(x, z, forced); - } - -@@ -958,6 +977,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) { -+ warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper - // Transient load for this tick - return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z); - } -@@ -2358,6 +2378,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - // Spigot end - // Paper start - public java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { -+ warnUnsafeChunk("getting a faraway chunk async", x, z); // Paper - if (Bukkit.isPrimaryThread()) { - net.minecraft.world.level.chunk.LevelChunk immediate = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); - if (immediate != null) { diff --git a/patches/server/0721-Add-and-fix-missing-BlockFadeEvents.patch b/patches/server/0721-Add-and-fix-missing-BlockFadeEvents.patch new file mode 100644 index 0000000000..1ac5d1e5ab --- /dev/null +++ b/patches/server/0721-Add-and-fix-missing-BlockFadeEvents.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Thu, 21 Jul 2022 12:07:54 -0400 +Subject: [PATCH] Add and fix missing BlockFadeEvents + +Beyond calling the BlockFadeEvent in more places, this patch also aims +to pass the proper replacement state to the event, specifically for +potentially waterlogged block states fading. + +Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> + +diff --git a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java +index 34be6b349722240e99f91d28067578aa0b4bd1fe..4f53f25d7565eb930f6ae27ca24a6aa0cca571a2 100644 +--- a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java +@@ -102,6 +102,11 @@ public class FrogspawnBlock extends Block { + } + + private void hatchFrogspawn(ServerLevel world, BlockPos pos, RandomSource random) { ++ // Paper start - Call BlockFadeEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.AIR.defaultBlockState()).isCancelled()) { ++ return; ++ } ++ // Paper end - Call BlockFadeEvent + this.destroyBlock(world, pos); + world.playSound(null, pos, SoundEvents.FROGSPAWN_HATCH, SoundSource.BLOCKS, 1.0F, 1.0F); + this.spawnTadpoles(world, pos, random); +diff --git a/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java b/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java +index fc49230d6b2c13b009724d28081f5e77537d5ab8..2d3f425778302490dd3654d487cfa3cfed6fb9e8 100644 +--- a/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java +@@ -103,7 +103,7 @@ public class ScaffoldingBlock extends Block implements SimpleWaterloggedBlock { + int i = ScaffoldingBlock.getDistance(world, pos); + BlockState iblockdata1 = (BlockState) ((BlockState) state.setValue(ScaffoldingBlock.DISTANCE, i)).setValue(ScaffoldingBlock.BOTTOM, this.isBottom(world, pos, i)); + +- if ((Integer) iblockdata1.getValue(ScaffoldingBlock.DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.AIR.defaultBlockState()).isCancelled()) { // CraftBukkit - BlockFadeEvent ++ if ((Integer) iblockdata1.getValue(ScaffoldingBlock.DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, iblockdata1.getFluidState().createLegacyBlock()).isCancelled()) { // CraftBukkit - BlockFadeEvent // Paper - fix wrong block state + if ((Integer) state.getValue(ScaffoldingBlock.DISTANCE) == 7) { + FallingBlockEntity.fall(world, pos, iblockdata1); + } else { +diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java +index 4f8224841865f956aaa969ab7f543c80b3c24319..2df28caefff893f319924ae5fd376c8aeb0a2158 100644 +--- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java +@@ -61,12 +61,26 @@ public class SnifferEggBlock extends Block { + return this.getHatchLevel(state) == 2; + } + ++ // Paper start - Call BlockFadeEvent ++ private void rescheduleTick(ServerLevel world, BlockPos pos) { ++ int baseDelay = hatchBoost(world, pos) ? BOOSTED_HATCH_TIME_TICKS : REGULAR_HATCH_TIME_TICKS; ++ world.scheduleTick(pos, this, (baseDelay / 3) + world.random.nextInt(RANDOM_HATCH_OFFSET_TICKS)); ++ // reschedule to avoid being stuck here and behave like the other calls (see #onPlace) ++ } ++ // Paper end - Call BlockFadeEvent ++ + @Override + public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { + if (!this.isReadyToHatch(state)) { + world.playSound(null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); + world.setBlock(pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2); + } else { ++ // Paper start - Call BlockFadeEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, state.getFluidState().createLegacyBlock()).isCancelled()) { ++ this.rescheduleTick(world, pos); ++ return; ++ } ++ // Paper end - Call BlockFadeEvent + world.playSound(null, pos, SoundEvents.SNIFFER_EGG_HATCH, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); + world.destroyBlock(pos, false); + Sniffer sniffer = EntityType.SNIFFER.create(world, EntitySpawnReason.BREEDING); diff --git a/patches/server/0721-Custom-Chat-Completion-Suggestions-API.patch b/patches/server/0721-Custom-Chat-Completion-Suggestions-API.patch deleted file mode 100644 index 9908dc279c..0000000000 --- a/patches/server/0721-Custom-Chat-Completion-Suggestions-API.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sat, 30 Jul 2022 11:23:05 -0400 -Subject: [PATCH] Custom Chat Completion Suggestions API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index baae7a129853a296273b7f295f58cbb99187da22..58f3ca95b1d79269bed3b6473cd69d8988ede162 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -708,6 +708,24 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - // Paper end - Add sendOpLevel API - -+ // Paper start - custom chat completions API -+ @Override -+ public void addAdditionalChatCompletions(@NotNull Collection completions) { -+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket( -+ net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket.Action.ADD, -+ new ArrayList<>(completions) -+ )); -+ } -+ -+ @Override -+ public void removeAdditionalChatCompletions(@NotNull Collection completions) { -+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket( -+ net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket.Action.REMOVE, -+ new ArrayList<>(completions) -+ )); -+ } -+ // Paper end - custom chat completions API -+ - @Override - public void setCompassTarget(Location loc) { - Preconditions.checkArgument(loc != null, "Location cannot be null"); diff --git a/patches/server/0722-Add-and-fix-missing-BlockFadeEvents.patch b/patches/server/0722-Add-and-fix-missing-BlockFadeEvents.patch deleted file mode 100644 index 1ac5d1e5ab..0000000000 --- a/patches/server/0722-Add-and-fix-missing-BlockFadeEvents.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Thu, 21 Jul 2022 12:07:54 -0400 -Subject: [PATCH] Add and fix missing BlockFadeEvents - -Beyond calling the BlockFadeEvent in more places, this patch also aims -to pass the proper replacement state to the event, specifically for -potentially waterlogged block states fading. - -Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> - -diff --git a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java -index 34be6b349722240e99f91d28067578aa0b4bd1fe..4f53f25d7565eb930f6ae27ca24a6aa0cca571a2 100644 ---- a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java -@@ -102,6 +102,11 @@ public class FrogspawnBlock extends Block { - } - - private void hatchFrogspawn(ServerLevel world, BlockPos pos, RandomSource random) { -+ // Paper start - Call BlockFadeEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.AIR.defaultBlockState()).isCancelled()) { -+ return; -+ } -+ // Paper end - Call BlockFadeEvent - this.destroyBlock(world, pos); - world.playSound(null, pos, SoundEvents.FROGSPAWN_HATCH, SoundSource.BLOCKS, 1.0F, 1.0F); - this.spawnTadpoles(world, pos, random); -diff --git a/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java b/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java -index fc49230d6b2c13b009724d28081f5e77537d5ab8..2d3f425778302490dd3654d487cfa3cfed6fb9e8 100644 ---- a/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java -@@ -103,7 +103,7 @@ public class ScaffoldingBlock extends Block implements SimpleWaterloggedBlock { - int i = ScaffoldingBlock.getDistance(world, pos); - BlockState iblockdata1 = (BlockState) ((BlockState) state.setValue(ScaffoldingBlock.DISTANCE, i)).setValue(ScaffoldingBlock.BOTTOM, this.isBottom(world, pos, i)); - -- if ((Integer) iblockdata1.getValue(ScaffoldingBlock.DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.AIR.defaultBlockState()).isCancelled()) { // CraftBukkit - BlockFadeEvent -+ if ((Integer) iblockdata1.getValue(ScaffoldingBlock.DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, iblockdata1.getFluidState().createLegacyBlock()).isCancelled()) { // CraftBukkit - BlockFadeEvent // Paper - fix wrong block state - if ((Integer) state.getValue(ScaffoldingBlock.DISTANCE) == 7) { - FallingBlockEntity.fall(world, pos, iblockdata1); - } else { -diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -index 4f8224841865f956aaa969ab7f543c80b3c24319..2df28caefff893f319924ae5fd376c8aeb0a2158 100644 ---- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -@@ -61,12 +61,26 @@ public class SnifferEggBlock extends Block { - return this.getHatchLevel(state) == 2; - } - -+ // Paper start - Call BlockFadeEvent -+ private void rescheduleTick(ServerLevel world, BlockPos pos) { -+ int baseDelay = hatchBoost(world, pos) ? BOOSTED_HATCH_TIME_TICKS : REGULAR_HATCH_TIME_TICKS; -+ world.scheduleTick(pos, this, (baseDelay / 3) + world.random.nextInt(RANDOM_HATCH_OFFSET_TICKS)); -+ // reschedule to avoid being stuck here and behave like the other calls (see #onPlace) -+ } -+ // Paper end - Call BlockFadeEvent -+ - @Override - public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { - if (!this.isReadyToHatch(state)) { - world.playSound(null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); - world.setBlock(pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2); - } else { -+ // Paper start - Call BlockFadeEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, state.getFluidState().createLegacyBlock()).isCancelled()) { -+ this.rescheduleTick(world, pos); -+ return; -+ } -+ // Paper end - Call BlockFadeEvent - world.playSound(null, pos, SoundEvents.SNIFFER_EGG_HATCH, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); - world.destroyBlock(pos, false); - Sniffer sniffer = EntityType.SNIFFER.create(world, EntitySpawnReason.BREEDING); diff --git a/patches/server/0722-Collision-API.patch b/patches/server/0722-Collision-API.patch new file mode 100644 index 0000000000..6f4b6366a8 --- /dev/null +++ b/patches/server/0722-Collision-API.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 6 Oct 2021 20:10:44 -0400 +Subject: [PATCH] Collision API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +index a7748f4b7c5a1630937c702b3fd5fded93793d64..a93a879117ee1eb06842242aa03f757a4a676946 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +@@ -549,5 +549,12 @@ public abstract class CraftRegionAccessor implements RegionAccessor { + + return this.getHandle().clip(new net.minecraft.world.level.ClipContext(start, end, net.minecraft.world.level.ClipContext.Block.COLLIDER, net.minecraft.world.level.ClipContext.Fluid.NONE, net.minecraft.world.phys.shapes.CollisionContext.empty())).getType() == net.minecraft.world.phys.HitResult.Type.MISS; + } ++ ++ @Override ++ public boolean hasCollisionsIn(@org.jetbrains.annotations.NotNull org.bukkit.util.BoundingBox boundingBox) { ++ net.minecraft.world.phys.AABB aabb = new net.minecraft.world.phys.AABB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); ++ ++ return !this.getHandle().noCollision(aabb); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index a314e401ee8a306dc12a2d98a3d400ae611a6e5a..01513cd747a0e18e3839e83bf5795aadb7d1e0e9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1194,4 +1194,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return this.getHandle().noPhysics; + } + // Paper end - missing entity api ++ ++ // Paper start - Collision API ++ @Override ++ public boolean collidesAt(@org.jetbrains.annotations.NotNull Location location) { ++ net.minecraft.world.phys.AABB aabb = this.getHandle().getBoundingBoxAt(location.getX(), location.getY(), location.getZ()); ++ ++ return !this.getHandle().level().noCollision(this.getHandle(), aabb); ++ } ++ ++ @Override ++ public boolean wouldCollideUsing(@org.jetbrains.annotations.NotNull BoundingBox boundingBox) { ++ net.minecraft.world.phys.AABB aabb = new AABB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); ++ ++ return !this.getHandle().level().noCollision(this.getHandle(), aabb); ++ } ++ // Paper end - Collision API + } diff --git a/patches/server/0723-Collision-API.patch b/patches/server/0723-Collision-API.patch deleted file mode 100644 index 6f4b6366a8..0000000000 --- a/patches/server/0723-Collision-API.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 6 Oct 2021 20:10:44 -0400 -Subject: [PATCH] Collision API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -index a7748f4b7c5a1630937c702b3fd5fded93793d64..a93a879117ee1eb06842242aa03f757a4a676946 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -@@ -549,5 +549,12 @@ public abstract class CraftRegionAccessor implements RegionAccessor { - - return this.getHandle().clip(new net.minecraft.world.level.ClipContext(start, end, net.minecraft.world.level.ClipContext.Block.COLLIDER, net.minecraft.world.level.ClipContext.Fluid.NONE, net.minecraft.world.phys.shapes.CollisionContext.empty())).getType() == net.minecraft.world.phys.HitResult.Type.MISS; - } -+ -+ @Override -+ public boolean hasCollisionsIn(@org.jetbrains.annotations.NotNull org.bukkit.util.BoundingBox boundingBox) { -+ net.minecraft.world.phys.AABB aabb = new net.minecraft.world.phys.AABB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); -+ -+ return !this.getHandle().noCollision(aabb); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index a314e401ee8a306dc12a2d98a3d400ae611a6e5a..01513cd747a0e18e3839e83bf5795aadb7d1e0e9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1194,4 +1194,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return this.getHandle().noPhysics; - } - // Paper end - missing entity api -+ -+ // Paper start - Collision API -+ @Override -+ public boolean collidesAt(@org.jetbrains.annotations.NotNull Location location) { -+ net.minecraft.world.phys.AABB aabb = this.getHandle().getBoundingBoxAt(location.getX(), location.getY(), location.getZ()); -+ -+ return !this.getHandle().level().noCollision(this.getHandle(), aabb); -+ } -+ -+ @Override -+ public boolean wouldCollideUsing(@org.jetbrains.annotations.NotNull BoundingBox boundingBox) { -+ net.minecraft.world.phys.AABB aabb = new AABB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); -+ -+ return !this.getHandle().level().noCollision(this.getHandle(), aabb); -+ } -+ // Paper end - Collision API - } diff --git a/patches/server/0723-Fix-suggest-command-message-for-brigadier-syntax-exc.patch b/patches/server/0723-Fix-suggest-command-message-for-brigadier-syntax-exc.patch new file mode 100644 index 0000000000..34f5fa3e3d --- /dev/null +++ b/patches/server/0723-Fix-suggest-command-message-for-brigadier-syntax-exc.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chickeneer +Date: Mon, 1 Aug 2022 20:13:02 -0500 +Subject: [PATCH] Fix suggest command message for brigadier syntax exceptions + +This is a bug accidentally introduced in upstream CB + +diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java +index bee79fab7f8195e14f6bd22d9cd59bfc704bf903..fd12046fab797fd845ad8521f94147480dfba5da 100644 +--- a/src/main/java/net/minecraft/commands/Commands.java ++++ b/src/main/java/net/minecraft/commands/Commands.java +@@ -391,7 +391,7 @@ public class Commands { + if (commandsyntaxexception.getInput() != null && commandsyntaxexception.getCursor() >= 0) { + int i = Math.min(commandsyntaxexception.getInput().length(), commandsyntaxexception.getCursor()); + MutableComponent ichatmutablecomponent = Component.empty().withStyle(ChatFormatting.GRAY).withStyle((chatmodifier) -> { +- return chatmodifier.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, label)); // CraftBukkit ++ return chatmodifier.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + label)); // CraftBukkit // Paper + }); + + if (i > 10) { diff --git a/patches/server/0724-Block-Ticking-API.patch b/patches/server/0724-Block-Ticking-API.patch new file mode 100644 index 0000000000..c2a5c23d6c --- /dev/null +++ b/patches/server/0724-Block-Ticking-API.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 26 Dec 2021 13:23:46 -0500 +Subject: [PATCH] Block Ticking API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 68fcec085334383808b2117a49220f4d8239220b..7afb933782cac7e1ad621e80211c13066c680ad7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -78,6 +78,12 @@ public class CraftBlock implements Block { + return this.world.getBlockState(this.position); + } + ++ // Paper start ++ public net.minecraft.world.level.material.FluidState getNMSFluid() { ++ return this.world.getFluidState(this.position); ++ } ++ // Paper end ++ + public BlockPos getPosition() { + return this.position; + } +@@ -709,5 +715,23 @@ public class CraftBlock implements Block { + public boolean isValidTool(ItemStack itemStack) { + return getDrops(itemStack).size() != 0; + } ++ ++ @Override ++ public void tick() { ++ final ServerLevel level = this.world.getMinecraftWorld(); ++ this.getNMS().tick(level, this.position, level.random); ++ } ++ ++ ++ @Override ++ public void fluidTick() { ++ this.getNMSFluid().tick(this.world.getMinecraftWorld(), this.position, this.getNMS()); ++ } ++ ++ @Override ++ public void randomTick() { ++ final ServerLevel level = this.world.getMinecraftWorld(); ++ this.getNMS().randomTick(level, this.position, level.random); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +index a17c1d1651d4d36c40ef97c1cf0b1e0d61f53418..3ec64c995dcb59a758741e32b886925983a8be56 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +@@ -756,4 +756,11 @@ public class CraftBlockData implements BlockData { + return speed; + } + // Paper end - destroy speed API ++ ++ // Paper start - Block tick API ++ @Override ++ public boolean isRandomlyTicked() { ++ return this.state.isRandomlyTicking(); ++ } ++ // Paper end - Block tick API + } diff --git a/patches/server/0724-Fix-suggest-command-message-for-brigadier-syntax-exc.patch b/patches/server/0724-Fix-suggest-command-message-for-brigadier-syntax-exc.patch deleted file mode 100644 index 34f5fa3e3d..0000000000 --- a/patches/server/0724-Fix-suggest-command-message-for-brigadier-syntax-exc.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: chickeneer -Date: Mon, 1 Aug 2022 20:13:02 -0500 -Subject: [PATCH] Fix suggest command message for brigadier syntax exceptions - -This is a bug accidentally introduced in upstream CB - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index bee79fab7f8195e14f6bd22d9cd59bfc704bf903..fd12046fab797fd845ad8521f94147480dfba5da 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -391,7 +391,7 @@ public class Commands { - if (commandsyntaxexception.getInput() != null && commandsyntaxexception.getCursor() >= 0) { - int i = Math.min(commandsyntaxexception.getInput().length(), commandsyntaxexception.getCursor()); - MutableComponent ichatmutablecomponent = Component.empty().withStyle(ChatFormatting.GRAY).withStyle((chatmodifier) -> { -- return chatmodifier.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, label)); // CraftBukkit -+ return chatmodifier.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + label)); // CraftBukkit // Paper - }); - - if (i > 10) { diff --git a/patches/server/0725-Add-Velocity-IP-Forwarding-Support.patch b/patches/server/0725-Add-Velocity-IP-Forwarding-Support.patch new file mode 100644 index 0000000000..d5eb9544e5 --- /dev/null +++ b/patches/server/0725-Add-Velocity-IP-Forwarding-Support.patch @@ -0,0 +1,242 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn +Date: Mon, 8 Oct 2018 14:36:14 -0400 +Subject: [PATCH] Add Velocity IP Forwarding Support + +While Velocity supports BungeeCord-style IP forwarding, it is not secure. Users +have a lot of problems setting up firewalls or setting up plugins like IPWhitelist. +Further, the BungeeCord IP forwarding protocol still retains essentially its original +form, when there is brand new support for custom login plugin messages in 1.13. + +Velocity's modern IP forwarding uses an HMAC-SHA256 code to ensure authenticity +of messages, is packed into a binary format that is smaller than BungeeCord's +forwarding, and is integrated into the Minecraft login process by using the 1.13 +login plugin message packet. + +diff --git a/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java b/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1b797955357612a4319452de7461ba044cbb88d6 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java +@@ -0,0 +1,86 @@ ++package com.destroystokyo.paper.proxy; ++ ++import io.papermc.paper.configuration.GlobalConfiguration; ++import com.google.common.net.InetAddresses; ++import com.mojang.authlib.GameProfile; ++import com.mojang.authlib.properties.Property; ++import java.net.InetAddress; ++import java.security.InvalidKeyException; ++import java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.util.UUID; ++import javax.crypto.Mac; ++import javax.crypto.spec.SecretKeySpec; ++import net.minecraft.network.FriendlyByteBuf; ++import net.minecraft.network.protocol.login.custom.CustomQueryPayload; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.world.entity.player.ProfilePublicKey; ++ ++/** ++ * While Velocity supports BungeeCord-style IP forwarding, it is not secure. Users ++ * have a lot of problems setting up firewalls or setting up plugins like IPWhitelist. ++ * Further, the BungeeCord IP forwarding protocol still retains essentially its original ++ * form, when there is brand-new support for custom login plugin messages in 1.13. ++ *

++ * Velocity's modern IP forwarding uses an HMAC-SHA256 code to ensure authenticity ++ * of messages, is packed into a binary format that is smaller than BungeeCord's ++ * forwarding, and is integrated into the Minecraft login process by using the 1.13 ++ * login plugin message packet. ++ */ ++public class VelocityProxy { ++ private static final int SUPPORTED_FORWARDING_VERSION = 1; ++ public static final int MODERN_FORWARDING_WITH_KEY = 2; ++ public static final int MODERN_FORWARDING_WITH_KEY_V2 = 3; ++ public static final int MODERN_LAZY_SESSION = 4; ++ public static final byte MAX_SUPPORTED_FORWARDING_VERSION = MODERN_LAZY_SESSION; ++ public static final ResourceLocation PLAYER_INFO_CHANNEL = ResourceLocation.fromNamespaceAndPath("velocity", "player_info"); ++ ++ public static boolean checkIntegrity(final FriendlyByteBuf buf) { ++ final byte[] signature = new byte[32]; ++ buf.readBytes(signature); ++ ++ final byte[] data = new byte[buf.readableBytes()]; ++ buf.getBytes(buf.readerIndex(), data); ++ ++ try { ++ final Mac mac = Mac.getInstance("HmacSHA256"); ++ mac.init(new SecretKeySpec(GlobalConfiguration.get().proxies.velocity.secret.getBytes(java.nio.charset.StandardCharsets.UTF_8), "HmacSHA256")); ++ final byte[] mySignature = mac.doFinal(data); ++ if (!MessageDigest.isEqual(signature, mySignature)) { ++ return false; ++ } ++ } catch (final InvalidKeyException | NoSuchAlgorithmException e) { ++ throw new AssertionError(e); ++ } ++ ++ return true; ++ } ++ ++ public static InetAddress readAddress(final FriendlyByteBuf buf) { ++ return InetAddresses.forString(buf.readUtf(Short.MAX_VALUE)); ++ } ++ ++ public static GameProfile createProfile(final FriendlyByteBuf buf) { ++ final GameProfile profile = new GameProfile(buf.readUUID(), buf.readUtf(16)); ++ readProperties(buf, profile); ++ return profile; ++ } ++ ++ private static void readProperties(final FriendlyByteBuf buf, final GameProfile profile) { ++ final int properties = buf.readVarInt(); ++ for (int i1 = 0; i1 < properties; i1++) { ++ final String name = buf.readUtf(Short.MAX_VALUE); ++ final String value = buf.readUtf(Short.MAX_VALUE); ++ final String signature = buf.readBoolean() ? buf.readUtf(Short.MAX_VALUE) : null; ++ profile.getProperties().put(name, new Property(name, value, signature)); ++ } ++ } ++ ++ public static ProfilePublicKey.Data readForwardedKey(FriendlyByteBuf buf) { ++ return new ProfilePublicKey.Data(buf); ++ } ++ ++ public static UUID readSignerUuidOrElse(FriendlyByteBuf buf, UUID orElse) { ++ return buf.readBoolean() ? buf.readUUID() : orElse; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index ac7fc2497b860a143ef08498f5f477a373a29be7..4e47611f85f3db6a638d0fc6a0dd712b245cf229 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -288,13 +288,20 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.STARTUP); + // CraftBukkit end + ++ // Paper start - Add Velocity IP Forwarding Support ++ boolean usingProxy = org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled; ++ String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; ++ String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; ++ // Paper end - Add Velocity IP Forwarding Support + if (!this.usesAuthentication()) { + DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); + // Spigot start +- if (org.spigotmc.SpigotConfig.bungee) { +- DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); +- DedicatedServer.LOGGER.warn("Please see http://www.spigotmc.org/wiki/firewall-guide/ for further information."); ++ // Paper start - Add Velocity IP Forwarding Support ++ if (usingProxy) { ++ DedicatedServer.LOGGER.warn("Whilst this makes it possible to use " + proxyFlavor + ", unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); ++ DedicatedServer.LOGGER.warn("Please see " + proxyLink + " for further information."); ++ // Paper end - Add Velocity IP Forwarding Support + } else { + DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); + } +diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index cb5dd77892283a1aaec45434fb99bb7f08ee5394..4a89b73d972f366e70f4d2bd96c6ee413593baba 100644 +--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -91,6 +91,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + private final boolean transferred; + private ServerPlayer player; // CraftBukkit + public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding ++ private int velocityLoginMessageId = -1; // Paper - Add Velocity IP Forwarding Support + + public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { + this.state = ServerLoginPacketListenerImpl.State.HELLO; +@@ -189,6 +190,16 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + this.state = ServerLoginPacketListenerImpl.State.KEY; + this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.challenge, true)); + } else { ++ // Paper start - Add Velocity IP Forwarding Support ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { ++ this.velocityLoginMessageId = java.util.concurrent.ThreadLocalRandom.current().nextInt(); ++ net.minecraft.network.FriendlyByteBuf buf = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.buffer()); ++ buf.writeByte(com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION); ++ net.minecraft.network.protocol.login.ClientboundCustomQueryPacket packet1 = new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket(this.velocityLoginMessageId, new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket.PlayerInfoChannelPayload(com.destroystokyo.paper.proxy.VelocityProxy.PLAYER_INFO_CHANNEL, buf)); ++ this.connection.send(packet1); ++ return; ++ } ++ // Paper end - Add Velocity IP Forwarding Support + // CraftBukkit start + // Paper start - Cache authenticator threads + authenticatorPool.execute(new Runnable() { +@@ -341,6 +352,12 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + + // CraftBukkit start + private GameProfile callPlayerPreLoginEvents(GameProfile gameprofile) throws Exception { // Paper - Add more fields to AsyncPlayerPreLoginEvent ++ // Paper start - Add Velocity IP Forwarding Support ++ if (ServerLoginPacketListenerImpl.this.velocityLoginMessageId == -1 && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { ++ disconnect("This server requires you to connect with Velocity."); ++ return gameprofile; ++ } ++ // Paper end - Add Velocity IP Forwarding Support + String playerName = gameprofile.getName(); + java.net.InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress(); + java.util.UUID uniqueId = gameprofile.getId(); +@@ -386,6 +403,51 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + + @Override + public void handleCustomQueryPacket(ServerboundCustomQueryAnswerPacket packet) { ++ // Paper start - Add Velocity IP Forwarding Support ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && packet.transactionId() == this.velocityLoginMessageId) { ++ ServerboundCustomQueryAnswerPacket.QueryAnswerPayload payload = (ServerboundCustomQueryAnswerPacket.QueryAnswerPayload)packet.payload(); ++ if (payload == null) { ++ this.disconnect("This server requires you to connect with Velocity."); ++ return; ++ } ++ ++ net.minecraft.network.FriendlyByteBuf buf = payload.buffer; ++ ++ if (!com.destroystokyo.paper.proxy.VelocityProxy.checkIntegrity(buf)) { ++ this.disconnect("Unable to verify player details"); ++ return; ++ } ++ ++ int version = buf.readVarInt(); ++ if (version > com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION) { ++ throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted upto " + com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION); ++ } ++ ++ java.net.SocketAddress listening = this.connection.getRemoteAddress(); ++ int port = 0; ++ if (listening instanceof java.net.InetSocketAddress) { ++ port = ((java.net.InetSocketAddress) listening).getPort(); ++ } ++ this.connection.address = new java.net.InetSocketAddress(com.destroystokyo.paper.proxy.VelocityProxy.readAddress(buf), port); ++ ++ this.authenticatedProfile = com.destroystokyo.paper.proxy.VelocityProxy.createProfile(buf); ++ ++ //TODO Update handling for lazy sessions, might not even have to do anything? ++ ++ // Proceed with login ++ authenticatorPool.execute(() -> { ++ try { ++ final GameProfile gameprofile = this.callPlayerPreLoginEvents(this.authenticatedProfile); ++ ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId()); ++ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile); ++ } catch (Exception ex) { ++ disconnect("Failed to verify username!"); ++ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + this.authenticatedProfile.getName(), ex); ++ } ++ }); ++ return; ++ } ++ // Paper end - Add Velocity IP Forwarding Support + this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 3deb58f3cd2e29b51944ac81cb3e0e52ec496242..b84dc11212aba4c06375cdbefa91c09d86a2b957 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -848,7 +848,7 @@ public final class CraftServer implements Server { + @Override + public long getConnectionThrottle() { + // Spigot Start - Automatically set connection throttle for bungee configurations +- if (org.spigotmc.SpigotConfig.bungee) { ++ if (org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { // Paper - Add Velocity IP Forwarding Support + return -1; + } else { + return this.configuration.getInt("settings.connection-throttle"); diff --git a/patches/server/0725-Block-Ticking-API.patch b/patches/server/0725-Block-Ticking-API.patch deleted file mode 100644 index c2a5c23d6c..0000000000 --- a/patches/server/0725-Block-Ticking-API.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 26 Dec 2021 13:23:46 -0500 -Subject: [PATCH] Block Ticking API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 68fcec085334383808b2117a49220f4d8239220b..7afb933782cac7e1ad621e80211c13066c680ad7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -78,6 +78,12 @@ public class CraftBlock implements Block { - return this.world.getBlockState(this.position); - } - -+ // Paper start -+ public net.minecraft.world.level.material.FluidState getNMSFluid() { -+ return this.world.getFluidState(this.position); -+ } -+ // Paper end -+ - public BlockPos getPosition() { - return this.position; - } -@@ -709,5 +715,23 @@ public class CraftBlock implements Block { - public boolean isValidTool(ItemStack itemStack) { - return getDrops(itemStack).size() != 0; - } -+ -+ @Override -+ public void tick() { -+ final ServerLevel level = this.world.getMinecraftWorld(); -+ this.getNMS().tick(level, this.position, level.random); -+ } -+ -+ -+ @Override -+ public void fluidTick() { -+ this.getNMSFluid().tick(this.world.getMinecraftWorld(), this.position, this.getNMS()); -+ } -+ -+ @Override -+ public void randomTick() { -+ final ServerLevel level = this.world.getMinecraftWorld(); -+ this.getNMS().randomTick(level, this.position, level.random); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -index a17c1d1651d4d36c40ef97c1cf0b1e0d61f53418..3ec64c995dcb59a758741e32b886925983a8be56 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -@@ -756,4 +756,11 @@ public class CraftBlockData implements BlockData { - return speed; - } - // Paper end - destroy speed API -+ -+ // Paper start - Block tick API -+ @Override -+ public boolean isRandomlyTicked() { -+ return this.state.isRandomlyTicking(); -+ } -+ // Paper end - Block tick API - } diff --git a/patches/server/0726-Add-NamespacedKey-biome-methods.patch b/patches/server/0726-Add-NamespacedKey-biome-methods.patch new file mode 100644 index 0000000000..015b2064d9 --- /dev/null +++ b/patches/server/0726-Add-NamespacedKey-biome-methods.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josh Roy <10731363+JRoy@users.noreply.github.com> +Date: Sun, 14 Aug 2022 12:23:11 -0400 +Subject: [PATCH] Add NamespacedKey biome methods + +Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 1ab160c3d042be43df3bd19d095534b91c4c2f71..9f4124485dac3d029ec8247b64098042aa1a48d2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -587,6 +587,19 @@ public final class CraftMagicNumbers implements UnsafeValues { + var supplier = net.minecraft.world.entity.ai.attributes.DefaultAttributes.getSupplier((net.minecraft.world.entity.EntityType) net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getValue(CraftNamespacedKey.toMinecraft(bukkitEntityKey))); + return new io.papermc.paper.attribute.UnmodifiableAttributeMap(supplier); + } ++ ++ @Override ++ public org.bukkit.NamespacedKey getBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z) { ++ org.bukkit.craftbukkit.CraftRegionAccessor cra = (org.bukkit.craftbukkit.CraftRegionAccessor) accessor; ++ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(cra.getHandle().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME).getKey(cra.getHandle().getBiome(new net.minecraft.core.BlockPos(x, y, z)).value())); ++ } ++ ++ @Override ++ public void setBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z, org.bukkit.NamespacedKey biomeKey) { ++ org.bukkit.craftbukkit.CraftRegionAccessor cra = (org.bukkit.craftbukkit.CraftRegionAccessor) accessor; ++ net.minecraft.core.Holder biomeBase = cra.getHandle().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME).getOrThrow(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.BIOME, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(biomeKey))); ++ cra.setBiome(x, y, z, biomeBase); ++ } + // Paper end + + /** diff --git a/patches/server/0726-Add-Velocity-IP-Forwarding-Support.patch b/patches/server/0726-Add-Velocity-IP-Forwarding-Support.patch deleted file mode 100644 index cba81cdb0f..0000000000 --- a/patches/server/0726-Add-Velocity-IP-Forwarding-Support.patch +++ /dev/null @@ -1,242 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Steinborn -Date: Mon, 8 Oct 2018 14:36:14 -0400 -Subject: [PATCH] Add Velocity IP Forwarding Support - -While Velocity supports BungeeCord-style IP forwarding, it is not secure. Users -have a lot of problems setting up firewalls or setting up plugins like IPWhitelist. -Further, the BungeeCord IP forwarding protocol still retains essentially its original -form, when there is brand new support for custom login plugin messages in 1.13. - -Velocity's modern IP forwarding uses an HMAC-SHA256 code to ensure authenticity -of messages, is packed into a binary format that is smaller than BungeeCord's -forwarding, and is integrated into the Minecraft login process by using the 1.13 -login plugin message packet. - -diff --git a/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java b/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1b797955357612a4319452de7461ba044cbb88d6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java -@@ -0,0 +1,86 @@ -+package com.destroystokyo.paper.proxy; -+ -+import io.papermc.paper.configuration.GlobalConfiguration; -+import com.google.common.net.InetAddresses; -+import com.mojang.authlib.GameProfile; -+import com.mojang.authlib.properties.Property; -+import java.net.InetAddress; -+import java.security.InvalidKeyException; -+import java.security.MessageDigest; -+import java.security.NoSuchAlgorithmException; -+import java.util.UUID; -+import javax.crypto.Mac; -+import javax.crypto.spec.SecretKeySpec; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.login.custom.CustomQueryPayload; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.world.entity.player.ProfilePublicKey; -+ -+/** -+ * While Velocity supports BungeeCord-style IP forwarding, it is not secure. Users -+ * have a lot of problems setting up firewalls or setting up plugins like IPWhitelist. -+ * Further, the BungeeCord IP forwarding protocol still retains essentially its original -+ * form, when there is brand-new support for custom login plugin messages in 1.13. -+ *

-+ * Velocity's modern IP forwarding uses an HMAC-SHA256 code to ensure authenticity -+ * of messages, is packed into a binary format that is smaller than BungeeCord's -+ * forwarding, and is integrated into the Minecraft login process by using the 1.13 -+ * login plugin message packet. -+ */ -+public class VelocityProxy { -+ private static final int SUPPORTED_FORWARDING_VERSION = 1; -+ public static final int MODERN_FORWARDING_WITH_KEY = 2; -+ public static final int MODERN_FORWARDING_WITH_KEY_V2 = 3; -+ public static final int MODERN_LAZY_SESSION = 4; -+ public static final byte MAX_SUPPORTED_FORWARDING_VERSION = MODERN_LAZY_SESSION; -+ public static final ResourceLocation PLAYER_INFO_CHANNEL = ResourceLocation.fromNamespaceAndPath("velocity", "player_info"); -+ -+ public static boolean checkIntegrity(final FriendlyByteBuf buf) { -+ final byte[] signature = new byte[32]; -+ buf.readBytes(signature); -+ -+ final byte[] data = new byte[buf.readableBytes()]; -+ buf.getBytes(buf.readerIndex(), data); -+ -+ try { -+ final Mac mac = Mac.getInstance("HmacSHA256"); -+ mac.init(new SecretKeySpec(GlobalConfiguration.get().proxies.velocity.secret.getBytes(java.nio.charset.StandardCharsets.UTF_8), "HmacSHA256")); -+ final byte[] mySignature = mac.doFinal(data); -+ if (!MessageDigest.isEqual(signature, mySignature)) { -+ return false; -+ } -+ } catch (final InvalidKeyException | NoSuchAlgorithmException e) { -+ throw new AssertionError(e); -+ } -+ -+ return true; -+ } -+ -+ public static InetAddress readAddress(final FriendlyByteBuf buf) { -+ return InetAddresses.forString(buf.readUtf(Short.MAX_VALUE)); -+ } -+ -+ public static GameProfile createProfile(final FriendlyByteBuf buf) { -+ final GameProfile profile = new GameProfile(buf.readUUID(), buf.readUtf(16)); -+ readProperties(buf, profile); -+ return profile; -+ } -+ -+ private static void readProperties(final FriendlyByteBuf buf, final GameProfile profile) { -+ final int properties = buf.readVarInt(); -+ for (int i1 = 0; i1 < properties; i1++) { -+ final String name = buf.readUtf(Short.MAX_VALUE); -+ final String value = buf.readUtf(Short.MAX_VALUE); -+ final String signature = buf.readBoolean() ? buf.readUtf(Short.MAX_VALUE) : null; -+ profile.getProperties().put(name, new Property(name, value, signature)); -+ } -+ } -+ -+ public static ProfilePublicKey.Data readForwardedKey(FriendlyByteBuf buf) { -+ return new ProfilePublicKey.Data(buf); -+ } -+ -+ public static UUID readSignerUuidOrElse(FriendlyByteBuf buf, UUID orElse) { -+ return buf.readBoolean() ? buf.readUUID() : orElse; -+ } -+} -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 3c3be48b29fcd38c5dea1bfca8d8690850aa948e..4037a1057ebc87e3df6333e0d546fc85b5148d2a 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -290,13 +290,20 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.STARTUP); - // CraftBukkit end - -+ // Paper start - Add Velocity IP Forwarding Support -+ boolean usingProxy = org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled; -+ String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; -+ String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; -+ // Paper end - Add Velocity IP Forwarding Support - if (!this.usesAuthentication()) { - DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); - DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); - // Spigot start -- if (org.spigotmc.SpigotConfig.bungee) { -- DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); -- DedicatedServer.LOGGER.warn("Please see http://www.spigotmc.org/wiki/firewall-guide/ for further information."); -+ // Paper start - Add Velocity IP Forwarding Support -+ if (usingProxy) { -+ DedicatedServer.LOGGER.warn("Whilst this makes it possible to use " + proxyFlavor + ", unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); -+ DedicatedServer.LOGGER.warn("Please see " + proxyLink + " for further information."); -+ // Paper end - Add Velocity IP Forwarding Support - } else { - DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); - } -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index cb5dd77892283a1aaec45434fb99bb7f08ee5394..4a89b73d972f366e70f4d2bd96c6ee413593baba 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -91,6 +91,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - private final boolean transferred; - private ServerPlayer player; // CraftBukkit - public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding -+ private int velocityLoginMessageId = -1; // Paper - Add Velocity IP Forwarding Support - - public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { - this.state = ServerLoginPacketListenerImpl.State.HELLO; -@@ -189,6 +190,16 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - this.state = ServerLoginPacketListenerImpl.State.KEY; - this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.challenge, true)); - } else { -+ // Paper start - Add Velocity IP Forwarding Support -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { -+ this.velocityLoginMessageId = java.util.concurrent.ThreadLocalRandom.current().nextInt(); -+ net.minecraft.network.FriendlyByteBuf buf = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.buffer()); -+ buf.writeByte(com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION); -+ net.minecraft.network.protocol.login.ClientboundCustomQueryPacket packet1 = new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket(this.velocityLoginMessageId, new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket.PlayerInfoChannelPayload(com.destroystokyo.paper.proxy.VelocityProxy.PLAYER_INFO_CHANNEL, buf)); -+ this.connection.send(packet1); -+ return; -+ } -+ // Paper end - Add Velocity IP Forwarding Support - // CraftBukkit start - // Paper start - Cache authenticator threads - authenticatorPool.execute(new Runnable() { -@@ -341,6 +352,12 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - - // CraftBukkit start - private GameProfile callPlayerPreLoginEvents(GameProfile gameprofile) throws Exception { // Paper - Add more fields to AsyncPlayerPreLoginEvent -+ // Paper start - Add Velocity IP Forwarding Support -+ if (ServerLoginPacketListenerImpl.this.velocityLoginMessageId == -1 && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { -+ disconnect("This server requires you to connect with Velocity."); -+ return gameprofile; -+ } -+ // Paper end - Add Velocity IP Forwarding Support - String playerName = gameprofile.getName(); - java.net.InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress(); - java.util.UUID uniqueId = gameprofile.getId(); -@@ -386,6 +403,51 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - - @Override - public void handleCustomQueryPacket(ServerboundCustomQueryAnswerPacket packet) { -+ // Paper start - Add Velocity IP Forwarding Support -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && packet.transactionId() == this.velocityLoginMessageId) { -+ ServerboundCustomQueryAnswerPacket.QueryAnswerPayload payload = (ServerboundCustomQueryAnswerPacket.QueryAnswerPayload)packet.payload(); -+ if (payload == null) { -+ this.disconnect("This server requires you to connect with Velocity."); -+ return; -+ } -+ -+ net.minecraft.network.FriendlyByteBuf buf = payload.buffer; -+ -+ if (!com.destroystokyo.paper.proxy.VelocityProxy.checkIntegrity(buf)) { -+ this.disconnect("Unable to verify player details"); -+ return; -+ } -+ -+ int version = buf.readVarInt(); -+ if (version > com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION) { -+ throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted upto " + com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION); -+ } -+ -+ java.net.SocketAddress listening = this.connection.getRemoteAddress(); -+ int port = 0; -+ if (listening instanceof java.net.InetSocketAddress) { -+ port = ((java.net.InetSocketAddress) listening).getPort(); -+ } -+ this.connection.address = new java.net.InetSocketAddress(com.destroystokyo.paper.proxy.VelocityProxy.readAddress(buf), port); -+ -+ this.authenticatedProfile = com.destroystokyo.paper.proxy.VelocityProxy.createProfile(buf); -+ -+ //TODO Update handling for lazy sessions, might not even have to do anything? -+ -+ // Proceed with login -+ authenticatorPool.execute(() -> { -+ try { -+ final GameProfile gameprofile = this.callPlayerPreLoginEvents(this.authenticatedProfile); -+ ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId()); -+ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile); -+ } catch (Exception ex) { -+ disconnect("Failed to verify username!"); -+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + this.authenticatedProfile.getName(), ex); -+ } -+ }); -+ return; -+ } -+ // Paper end - Add Velocity IP Forwarding Support - this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 0c037618005265ed6b9533ea60848753141d8e0b..ff7bd67f593bbaabb5eb4c2b845acb2d428f1670 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -849,7 +849,7 @@ public final class CraftServer implements Server { - @Override - public long getConnectionThrottle() { - // Spigot Start - Automatically set connection throttle for bungee configurations -- if (org.spigotmc.SpigotConfig.bungee) { -+ if (org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { // Paper - Add Velocity IP Forwarding Support - return -1; - } else { - return this.configuration.getInt("settings.connection-throttle"); diff --git a/patches/server/0727-Add-NamespacedKey-biome-methods.patch b/patches/server/0727-Add-NamespacedKey-biome-methods.patch deleted file mode 100644 index 547d0fb0b7..0000000000 --- a/patches/server/0727-Add-NamespacedKey-biome-methods.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Josh Roy <10731363+JRoy@users.noreply.github.com> -Date: Sun, 14 Aug 2022 12:23:11 -0400 -Subject: [PATCH] Add NamespacedKey biome methods - -Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 8d51786837448db1a96d0071293025d07e14c225..9e0af05e066132b66fafff84ff0a0957c1a44f9f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -584,6 +584,21 @@ public final class CraftMagicNumbers implements UnsafeValues { - } - // Paper end - -+ // Paper start - namespaced key biome methods -+ @Override -+ public org.bukkit.NamespacedKey getBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z) { -+ org.bukkit.craftbukkit.CraftRegionAccessor cra = (org.bukkit.craftbukkit.CraftRegionAccessor) accessor; -+ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(cra.getHandle().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME).getKey(cra.getHandle().getBiome(new net.minecraft.core.BlockPos(x, y, z)).value())); -+ } -+ -+ @Override -+ public void setBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z, org.bukkit.NamespacedKey biomeKey) { -+ org.bukkit.craftbukkit.CraftRegionAccessor cra = (org.bukkit.craftbukkit.CraftRegionAccessor) accessor; -+ net.minecraft.core.Holder biomeBase = cra.getHandle().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME).getOrThrow(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.BIOME, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(biomeKey))); -+ cra.setBiome(x, y, z, biomeBase); -+ } -+ // Paper end - namespaced key biome methods -+ - @Override - public String get(Class aClass, String s) { - if (aClass == Enchantment.class) { diff --git a/patches/server/0727-Fix-plugin-loggers-on-server-shutdown.patch b/patches/server/0727-Fix-plugin-loggers-on-server-shutdown.patch new file mode 100644 index 0000000000..7f6f4755d1 --- /dev/null +++ b/patches/server/0727-Fix-plugin-loggers-on-server-shutdown.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Miguel=20Moreno?= +Date: Sat, 5 Jun 2021 13:45:15 +0200 +Subject: [PATCH] Fix plugin loggers on server shutdown + + +diff --git a/src/main/java/io/papermc/paper/log/CustomLogManager.java b/src/main/java/io/papermc/paper/log/CustomLogManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c1d3bac79bb8b4796c013ff4472f75dcd79602dc +--- /dev/null ++++ b/src/main/java/io/papermc/paper/log/CustomLogManager.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.log; ++ ++import java.util.logging.LogManager; ++ ++public class CustomLogManager extends LogManager { ++ private static CustomLogManager instance; ++ ++ public CustomLogManager() { ++ instance = this; ++ } ++ ++ @Override ++ public void reset() { ++ // Ignore calls to this method ++ } ++ ++ private void superReset() { ++ super.reset(); ++ } ++ ++ public static void forceReset() { ++ if (instance != null) { ++ instance.superReset(); ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index aa9a4a0f35d0200777bdc83520ba82a970bfa900..cb40a2d855e7ac8c1c8b4ec679fd057a31f3fc6f 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1277,6 +1277,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Sat, 5 Jun 2021 13:45:15 +0200 -Subject: [PATCH] Fix plugin loggers on server shutdown - - -diff --git a/src/main/java/io/papermc/paper/log/CustomLogManager.java b/src/main/java/io/papermc/paper/log/CustomLogManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c1d3bac79bb8b4796c013ff4472f75dcd79602dc ---- /dev/null -+++ b/src/main/java/io/papermc/paper/log/CustomLogManager.java -@@ -0,0 +1,26 @@ -+package io.papermc.paper.log; -+ -+import java.util.logging.LogManager; -+ -+public class CustomLogManager extends LogManager { -+ private static CustomLogManager instance; -+ -+ public CustomLogManager() { -+ instance = this; -+ } -+ -+ @Override -+ public void reset() { -+ // Ignore calls to this method -+ } -+ -+ private void superReset() { -+ super.reset(); -+ } -+ -+ public static void forceReset() { -+ if (instance != null) { -+ instance.superReset(); -+ } -+ } -+} -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 8fe1514bdc6b2e81a10e445952bd71afa5892552..57080f1343aa5408d70b320375813b00b205aafa 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1279,6 +1279,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Wed, 24 Aug 2022 09:54:11 -0400 +Subject: [PATCH] Stop large look changes from crashing the server + +Co-authored-by: Jaren Knodel + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 786ac2127bc743cf2a33776314a4b5c197f35538..b367f6e329f44801c6f0d34f447497093d86ae3b 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3270,37 +3270,15 @@ public abstract class LivingEntity extends Entity implements Attackable { + gameprofilerfiller.pop(); + gameprofilerfiller.push("rangeChecks"); + +- while (this.getYRot() - this.yRotO < -180.0F) { +- this.yRotO -= 360.0F; +- } +- +- while (this.getYRot() - this.yRotO >= 180.0F) { +- this.yRotO += 360.0F; +- } ++ // Paper start - stop large pitch and yaw changes from crashing the server ++ this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F; + +- while (this.yBodyRot - this.yBodyRotO < -180.0F) { +- this.yBodyRotO -= 360.0F; +- } ++ this.yBodyRotO += Math.round((this.yBodyRot - this.yBodyRotO) / 360.0F) * 360.0F; + +- while (this.yBodyRot - this.yBodyRotO >= 180.0F) { +- this.yBodyRotO += 360.0F; +- } +- +- while (this.getXRot() - this.xRotO < -180.0F) { +- this.xRotO -= 360.0F; +- } ++ this.xRotO += Math.round((this.getXRot() - this.xRotO) / 360.0F) * 360.0F; + +- while (this.getXRot() - this.xRotO >= 180.0F) { +- this.xRotO += 360.0F; +- } +- +- while (this.yHeadRot - this.yHeadRotO < -180.0F) { +- this.yHeadRotO -= 360.0F; +- } +- +- while (this.yHeadRot - this.yHeadRotO >= 180.0F) { +- this.yHeadRotO += 360.0F; +- } ++ this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F; ++ // Paper end + + gameprofilerfiller.pop(); + this.animStep += f2; +diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +index 824090367e833c57a22c1017981f0508b28a35d2..df0417f27bbf0f18f007746afe24fab48e2a0a08 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +@@ -428,13 +428,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { + } + + protected static float lerpRotation(float prevRot, float newRot) { +- while (newRot - prevRot < -180.0F) { +- prevRot -= 360.0F; +- } +- +- while (newRot - prevRot >= 180.0F) { +- prevRot += 360.0F; +- } ++ prevRot += Math.round((newRot - prevRot) / 360.0F) * 360.0F; // Paper - stop large look changes from crashing the server + + return Mth.lerp(0.2F, prevRot, newRot); + } diff --git a/patches/server/0729-Fire-EntityChangeBlockEvent-in-more-places.patch b/patches/server/0729-Fire-EntityChangeBlockEvent-in-more-places.patch new file mode 100644 index 0000000000..1d46619357 --- /dev/null +++ b/patches/server/0729-Fire-EntityChangeBlockEvent-in-more-places.patch @@ -0,0 +1,344 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 9 Aug 2021 20:45:46 -0700 +Subject: [PATCH] Fire EntityChangeBlockEvent in more places + +Co-authored-by: ChristopheG <61288881+chrisgdt@users.noreply.github.com> +Co-authored-by: maxcom1 <46265094+maxcom1@users.noreply.github.com> + +diff --git a/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java b/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java +index e311f94918fb03e9d202cbae71b0909ea3219180..b751748196b458c8a89d512fdd9f9632d25e8be8 100644 +--- a/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java ++++ b/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java +@@ -25,11 +25,11 @@ class WeavingMobEffect extends MobEffect { + @Override + public void onMobRemoved(ServerLevel world, LivingEntity entity, int amplifier, Entity.RemovalReason reason) { + if (reason == Entity.RemovalReason.KILLED && (entity instanceof Player || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { +- this.spawnCobwebsRandomlyAround(world, entity.getRandom(), entity.blockPosition()); ++ this.spawnCobwebsRandomlyAround(world, entity.getRandom(), entity.blockPosition(), entity); // Paper - Fire EntityChangeBlockEvent in more places + } + } + +- private void spawnCobwebsRandomlyAround(ServerLevel world, RandomSource random, BlockPos pos) { ++ private void spawnCobwebsRandomlyAround(ServerLevel world, RandomSource random, BlockPos pos, LivingEntity entity) { // Paper - Fire EntityChangeBlockEvent in more places + Set set = Sets.newHashSet(); + int i = this.maxCobwebs.applyAsInt(random); + +@@ -46,6 +46,7 @@ class WeavingMobEffect extends MobEffect { + } + + for (BlockPos blockPos3 : set) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPos3, Blocks.COBWEB.defaultBlockState())) continue; // Paper - Fire EntityChangeBlockEvent in more places + world.setBlock(blockPos3, Blocks.COBWEB.defaultBlockState(), 3); + world.levelEvent(3018, blockPos3, 0); + } +diff --git a/src/main/java/net/minecraft/world/entity/LightningBolt.java b/src/main/java/net/minecraft/world/entity/LightningBolt.java +index 2b09e9efad198ff596d88f97d703a8a00c108608..152ecd38814089333b8d61538297ce720756d2c3 100644 +--- a/src/main/java/net/minecraft/world/entity/LightningBolt.java ++++ b/src/main/java/net/minecraft/world/entity/LightningBolt.java +@@ -98,7 +98,7 @@ public class LightningBolt extends Entity { + } + + this.powerLightningRod(); +- LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition()); ++ LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition(), this); // Paper - Call EntityChangeBlockEvent + this.gameEvent(GameEvent.LIGHTNING_STRIKE); + } + } +@@ -202,7 +202,7 @@ public class LightningBolt extends Entity { + + } + +- private static void clearCopperOnLightningStrike(Level world, BlockPos pos) { ++ private static void clearCopperOnLightningStrike(Level world, BlockPos pos, Entity lightning) { // Paper - Call EntityChangeBlockEvent + BlockState iblockdata = world.getBlockState(pos); + BlockPos blockposition1; + BlockState iblockdata1; +@@ -216,24 +216,29 @@ public class LightningBolt extends Entity { + } + + if (iblockdata1.getBlock() instanceof WeatheringCopper) { +- world.setBlockAndUpdate(blockposition1, WeatheringCopper.getFirst(world.getBlockState(blockposition1))); ++ // Paper start - Call EntityChangeBlockEvent ++ BlockState newBlock = WeatheringCopper.getFirst(world.getBlockState(blockposition1)); ++ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1, newBlock)) { ++ world.setBlockAndUpdate(blockposition1, newBlock); ++ } ++ // Paper end - Call EntityChangeBlockEvent + BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); + int i = world.random.nextInt(3) + 3; + + for (int j = 0; j < i; ++j) { + int k = world.random.nextInt(8) + 1; + +- LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k); ++ LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + } + + } + } + +- private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count) { ++ private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + mutablePos.set(pos); + + for (int j = 0; j < count; ++j) { +- Optional optional = LightningBolt.randomStepCleaningCopper(world, mutablePos); ++ Optional optional = LightningBolt.randomStepCleaningCopper(world, mutablePos, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + + if (optional.isEmpty()) { + break; +@@ -244,7 +249,7 @@ public class LightningBolt extends Entity { + + } + +- private static Optional randomStepCleaningCopper(Level world, BlockPos pos) { ++ private static Optional randomStepCleaningCopper(Level world, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + Iterator iterator = BlockPos.randomInCube(world.random, 10, pos, 1).iterator(); + + BlockPos blockposition1; +@@ -261,6 +266,7 @@ public class LightningBolt extends Entity { + + BlockPos blockposition1Final = blockposition1; // CraftBukkit - decompile error + WeatheringCopper.getPrevious(iblockdata).ifPresent((iblockdata1) -> { ++ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1Final, iblockdata1)) // Paper - call EntityChangeBlockEvent + world.setBlockAndUpdate(blockposition1Final, iblockdata1); // CraftBukkit - decompile error + }); + world.levelEvent(3002, blockposition1, -1); +diff --git a/src/main/java/net/minecraft/world/item/AxeItem.java b/src/main/java/net/minecraft/world/item/AxeItem.java +index 74c9966093377b67e31b50483c2f24b70734faf6..abff08f2d61014944235ffe2f5494a718a28cc10 100644 +--- a/src/main/java/net/minecraft/world/item/AxeItem.java ++++ b/src/main/java/net/minecraft/world/item/AxeItem.java +@@ -67,6 +67,11 @@ public class AxeItem extends DiggerItem { + return InteractionResult.PASS; + } else { + ItemStack itemStack = context.getItemInHand(); ++ // Paper start - EntityChangeBlockEvent ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, optional.get())) { ++ return InteractionResult.PASS; ++ } ++ // Paper end + if (player instanceof ServerPlayer) { + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack); + } +diff --git a/src/main/java/net/minecraft/world/item/EnderEyeItem.java b/src/main/java/net/minecraft/world/item/EnderEyeItem.java +index 08cbf02bba3633a84cce90c202d13f2beb5b88a2..c71a426c47e0ebc57ecb8c9c1d171737a084ccab 100644 +--- a/src/main/java/net/minecraft/world/item/EnderEyeItem.java ++++ b/src/main/java/net/minecraft/world/item/EnderEyeItem.java +@@ -45,6 +45,11 @@ public class EnderEyeItem extends Item { + return InteractionResult.SUCCESS; + } else { + BlockState iblockdata1 = (BlockState) iblockdata.setValue(EndPortalFrameBlock.HAS_EYE, true); ++ // Paper start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockposition, iblockdata1)) { ++ return InteractionResult.PASS; ++ } ++ // Paper end + + Block.pushEntitiesUp(iblockdata, iblockdata1, world, blockposition); + world.setBlock(blockposition, iblockdata1, 2); +diff --git a/src/main/java/net/minecraft/world/item/HoneycombItem.java b/src/main/java/net/minecraft/world/item/HoneycombItem.java +index 6c0fe41692c9d1fa50a4f421eb4735860a9ae0e9..d7924825823b2bf79ca3a26272de11ff8d2ec74c 100644 +--- a/src/main/java/net/minecraft/world/item/HoneycombItem.java ++++ b/src/main/java/net/minecraft/world/item/HoneycombItem.java +@@ -74,6 +74,14 @@ public class HoneycombItem extends Item implements SignApplicator { + return getWaxed(blockState).map(state -> { + Player player = context.getPlayer(); + ItemStack itemStack = context.getItemInHand(); ++ // Paper start - EntityChangeBlockEvent ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, state)) { ++ if (!player.isCreative()) { ++ player.containerMenu.sendAllDataToRemote(); ++ } ++ return InteractionResult.PASS; ++ } ++ // Paper end + if (player instanceof ServerPlayer serverPlayer) { + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(serverPlayer, blockPos, itemStack); + } +diff --git a/src/main/java/net/minecraft/world/item/PotionItem.java b/src/main/java/net/minecraft/world/item/PotionItem.java +index 1c8fd643c32226d72d51abc869a49e256dd2432b..f19bd2c25d3c84d9f16cad38ac5c32736f0f3a8d 100644 +--- a/src/main/java/net/minecraft/world/item/PotionItem.java ++++ b/src/main/java/net/minecraft/world/item/PotionItem.java +@@ -42,6 +42,12 @@ public class PotionItem extends Item { + PotionContents potionContents = itemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + BlockState blockState = level.getBlockState(blockPos); + if (context.getClickedFace() != Direction.DOWN && blockState.is(BlockTags.CONVERTABLE_TO_MUD) && potionContents.is(Potions.WATER)) { ++ // Paper start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, Blocks.MUD.defaultBlockState())) { ++ player.containerMenu.sendAllDataToRemote(); ++ return InteractionResult.PASS; ++ } ++ // Paper end + level.playSound(null, blockPos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F); + player.setItemInHand(context.getHand(), ItemUtils.createFilledResult(itemStack, player, new ItemStack(Items.GLASS_BOTTLE))); + player.awardStat(Stats.ITEM_USED.get(itemStack.getItem())); +diff --git a/src/main/java/net/minecraft/world/item/ShovelItem.java b/src/main/java/net/minecraft/world/item/ShovelItem.java +index c0377341227e8f4f1f7b1448580b3c7bc1b65f48..55c18f182166f4905d623d6f5e909eefd5ed2483 100644 +--- a/src/main/java/net/minecraft/world/item/ShovelItem.java ++++ b/src/main/java/net/minecraft/world/item/ShovelItem.java +@@ -46,20 +46,29 @@ public class ShovelItem extends DiggerItem { + Player player = context.getPlayer(); + BlockState blockState2 = FLATTENABLES.get(blockState.getBlock()); + BlockState blockState3 = null; ++ Runnable afterAction = null; // Paper + if (blockState2 != null && level.getBlockState(blockPos.above()).isAir()) { +- level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); ++ afterAction = () -> level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper + blockState3 = blockState2; + } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { ++ afterAction = () -> { // Paper + if (!level.isClientSide()) { + level.levelEvent(null, 1009, blockPos, 0); + } + + CampfireBlock.dowse(context.getPlayer(), level, blockPos, blockState); ++ }; // Paper + blockState3 = blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false)); + } + + if (blockState3 != null) { + if (!level.isClientSide) { ++ // Paper start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockPos, blockState3)) { ++ return InteractionResult.PASS; ++ } ++ afterAction.run(); ++ // Paper end + level.setBlock(blockPos, blockState3, 11); + level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, blockState3)); + if (player != null) { +diff --git a/src/main/java/net/minecraft/world/level/block/CakeBlock.java b/src/main/java/net/minecraft/world/level/block/CakeBlock.java +index 7629b9212ded7155e94f67ca429f62271e5f5aa0..648c2510beb162e73aed236a3169d0bbb8fc5050 100644 +--- a/src/main/java/net/minecraft/world/level/block/CakeBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CakeBlock.java +@@ -66,6 +66,12 @@ public class CakeBlock extends Block { + if (block instanceof CandleBlock) { + CandleBlock candleblock = (CandleBlock) block; + ++ // Paper start - call change block event ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, CandleCakeBlock.byCandle(candleblock))) { ++ player.containerMenu.sendAllDataToRemote(); // update inv because candle could decrease ++ return InteractionResult.TRY_WITH_EMPTY_HAND; ++ } ++ // Paper end - call change block event + stack.consume(1, player); + world.playSound((Player) null, pos, SoundEvents.CAKE_ADD_CANDLE, SoundSource.BLOCKS, 1.0F, 1.0F); + world.setBlockAndUpdate(pos, CandleCakeBlock.byCandle(candleblock)); +@@ -97,6 +103,14 @@ public class CakeBlock extends Block { + if (!player.canEat(false)) { + return InteractionResult.PASS; + } else { ++ // Paper start - call change block event ++ int i = state.getValue(CakeBlock.BITES); ++ final BlockState newState = i < MAX_BITES ? state.setValue(CakeBlock.BITES, i + 1) : world.getFluidState(pos).createLegacyBlock(); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) { ++ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); ++ return InteractionResult.PASS; // return a non-consume result to cake blocks don't drop their candles ++ } ++ // Paper end - call change block event + player.awardStat(Stats.EAT_CAKE_SLICE); + // CraftBukkit start + // entityhuman.getFoodData().eat(2, 0.1F); +@@ -110,7 +124,7 @@ public class CakeBlock extends Block { + + ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); + // CraftBukkit end +- int i = (Integer) state.getValue(CakeBlock.BITES); ++ // Paper - move up + + world.gameEvent((Entity) player, (Holder) GameEvent.EAT, pos); + if (i < 6) { +diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +index 2bcd246a26dad560cf69682b29983d320ebf1884..05b2eab26e2dc8e143e9fff2dcec40cfe927a197 100644 +--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +@@ -243,6 +243,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + if (i < 8 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) { + if (i < 7 && !world.isClientSide) { + BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack); ++ // Paper start - handle cancelled events ++ if (iblockdata1 == null) { ++ return InteractionResult.PASS; ++ } ++ // Paper end + + world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0); + player.awardStat(Stats.ITEM_USED.get(stack.getItem())); +@@ -273,11 +278,16 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + if (i < 7 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) { + // CraftBukkit start + double rand = world.getRandom().nextDouble(); +- BlockState iblockdata1 = ComposterBlock.addItem(user, state, DummyGeneratorAccess.INSTANCE, pos, stack, rand); +- if (state == iblockdata1 || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(user, pos, iblockdata1)) { ++ BlockState iblockdata1 = null; // Paper ++ if (false && (state == iblockdata1 || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(user, pos, iblockdata1))) { // Paper - move event call into addItem + return state; + } + iblockdata1 = ComposterBlock.addItem(user, state, world, pos, stack, rand); ++ // Paper start - handle cancelled events ++ if (iblockdata1 == null) { ++ return state; ++ } ++ // Paper end + // CraftBukkit end + + stack.shrink(1); +@@ -318,11 +328,13 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + return iblockdata1; + } + ++ @Nullable // Paper + static BlockState addItem(@Nullable Entity user, BlockState state, LevelAccessor world, BlockPos pos, ItemStack stack) { + // CraftBukkit start + return ComposterBlock.addItem(user, state, world, pos, stack, world.getRandom().nextDouble()); + } + ++ @Nullable // Paper - make it nullable + static BlockState addItem(@Nullable Entity entity, BlockState iblockdata, LevelAccessor generatoraccess, BlockPos blockposition, ItemStack itemstack, double rand) { + // CraftBukkit end + int i = (Integer) iblockdata.getValue(ComposterBlock.LEVEL); +@@ -333,6 +345,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + } else { + int j = i + 1; + BlockState iblockdata1 = (BlockState) iblockdata.setValue(ComposterBlock.LEVEL, j); ++ // Paper start - move the EntityChangeBlockEvent here to avoid conflict later for the compost events ++ if (entity != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, iblockdata1)) { ++ return null; ++ } ++ // Paper end + + generatoraccess.setBlock(blockposition, iblockdata1, 3); + generatoraccess.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entity, iblockdata1)); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +index 8224d5bddb7f7893dee09222a673af54791abcfa..f8828dc8334af19d7b2118e8cf34d94be5e09ee8 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +@@ -260,7 +260,13 @@ public class BeehiveBlockEntity extends BlockEntity { + --j; + } + +- world.setBlockAndUpdate(blockposition, (BlockState) iblockdata.setValue(BeehiveBlock.HONEY_LEVEL, i + j)); ++ // Paper start - Fire EntityChangeBlockEvent in more places ++ BlockState newBlockState = iblockdata.setValue(BeehiveBlock.HONEY_LEVEL, i + j); ++ ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entitybee, blockposition, newBlockState)) { ++ world.setBlockAndUpdate(blockposition, newBlockState); ++ } ++ // Paper end - Fire EntityChangeBlockEvent in more places + } + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +index daf3c26fce7569761951bfd5594c6726d854a9ff..e8a73d34dbb372581b03018aade170a31c266099 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +@@ -120,7 +120,7 @@ public class DummyGeneratorAccess implements WorldGenLevel { + + @Override + public void gameEvent(Holder event, Vec3 emitterPos, GameEvent.Context emitter) { +- // Used by BlockComposter ++ // Used by ComposterBlock + } + + @Override diff --git a/patches/server/0729-Stop-large-look-changes-from-crashing-the-server.patch b/patches/server/0729-Stop-large-look-changes-from-crashing-the-server.patch deleted file mode 100644 index 712c234903..0000000000 --- a/patches/server/0729-Stop-large-look-changes-from-crashing-the-server.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MWHunter -Date: Wed, 24 Aug 2022 09:54:11 -0400 -Subject: [PATCH] Stop large look changes from crashing the server - -Co-authored-by: Jaren Knodel - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index d41c0f1aa501cbe17c88029bafbe034901f6d562..7705c791bfbb386f0b9f326c4b0ee0057ed0e6f5 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3272,37 +3272,15 @@ public abstract class LivingEntity extends Entity implements Attackable { - gameprofilerfiller.pop(); - gameprofilerfiller.push("rangeChecks"); - -- while (this.getYRot() - this.yRotO < -180.0F) { -- this.yRotO -= 360.0F; -- } -- -- while (this.getYRot() - this.yRotO >= 180.0F) { -- this.yRotO += 360.0F; -- } -+ // Paper start - stop large pitch and yaw changes from crashing the server -+ this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F; - -- while (this.yBodyRot - this.yBodyRotO < -180.0F) { -- this.yBodyRotO -= 360.0F; -- } -+ this.yBodyRotO += Math.round((this.yBodyRot - this.yBodyRotO) / 360.0F) * 360.0F; - -- while (this.yBodyRot - this.yBodyRotO >= 180.0F) { -- this.yBodyRotO += 360.0F; -- } -- -- while (this.getXRot() - this.xRotO < -180.0F) { -- this.xRotO -= 360.0F; -- } -+ this.xRotO += Math.round((this.getXRot() - this.xRotO) / 360.0F) * 360.0F; - -- while (this.getXRot() - this.xRotO >= 180.0F) { -- this.xRotO += 360.0F; -- } -- -- while (this.yHeadRot - this.yHeadRotO < -180.0F) { -- this.yHeadRotO -= 360.0F; -- } -- -- while (this.yHeadRot - this.yHeadRotO >= 180.0F) { -- this.yHeadRotO += 360.0F; -- } -+ this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F; -+ // Paper end - - gameprofilerfiller.pop(); - this.animStep += f2; -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 824090367e833c57a22c1017981f0508b28a35d2..df0417f27bbf0f18f007746afe24fab48e2a0a08 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -428,13 +428,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { - } - - protected static float lerpRotation(float prevRot, float newRot) { -- while (newRot - prevRot < -180.0F) { -- prevRot -= 360.0F; -- } -- -- while (newRot - prevRot >= 180.0F) { -- prevRot += 360.0F; -- } -+ prevRot += Math.round((newRot - prevRot) / 360.0F) * 360.0F; // Paper - stop large look changes from crashing the server - - return Mth.lerp(0.2F, prevRot, newRot); - } diff --git a/patches/server/0730-Fire-EntityChangeBlockEvent-in-more-places.patch b/patches/server/0730-Fire-EntityChangeBlockEvent-in-more-places.patch deleted file mode 100644 index 1d46619357..0000000000 --- a/patches/server/0730-Fire-EntityChangeBlockEvent-in-more-places.patch +++ /dev/null @@ -1,344 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 9 Aug 2021 20:45:46 -0700 -Subject: [PATCH] Fire EntityChangeBlockEvent in more places - -Co-authored-by: ChristopheG <61288881+chrisgdt@users.noreply.github.com> -Co-authored-by: maxcom1 <46265094+maxcom1@users.noreply.github.com> - -diff --git a/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java b/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java -index e311f94918fb03e9d202cbae71b0909ea3219180..b751748196b458c8a89d512fdd9f9632d25e8be8 100644 ---- a/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java -+++ b/src/main/java/net/minecraft/world/effect/WeavingMobEffect.java -@@ -25,11 +25,11 @@ class WeavingMobEffect extends MobEffect { - @Override - public void onMobRemoved(ServerLevel world, LivingEntity entity, int amplifier, Entity.RemovalReason reason) { - if (reason == Entity.RemovalReason.KILLED && (entity instanceof Player || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { -- this.spawnCobwebsRandomlyAround(world, entity.getRandom(), entity.blockPosition()); -+ this.spawnCobwebsRandomlyAround(world, entity.getRandom(), entity.blockPosition(), entity); // Paper - Fire EntityChangeBlockEvent in more places - } - } - -- private void spawnCobwebsRandomlyAround(ServerLevel world, RandomSource random, BlockPos pos) { -+ private void spawnCobwebsRandomlyAround(ServerLevel world, RandomSource random, BlockPos pos, LivingEntity entity) { // Paper - Fire EntityChangeBlockEvent in more places - Set set = Sets.newHashSet(); - int i = this.maxCobwebs.applyAsInt(random); - -@@ -46,6 +46,7 @@ class WeavingMobEffect extends MobEffect { - } - - for (BlockPos blockPos3 : set) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPos3, Blocks.COBWEB.defaultBlockState())) continue; // Paper - Fire EntityChangeBlockEvent in more places - world.setBlock(blockPos3, Blocks.COBWEB.defaultBlockState(), 3); - world.levelEvent(3018, blockPos3, 0); - } -diff --git a/src/main/java/net/minecraft/world/entity/LightningBolt.java b/src/main/java/net/minecraft/world/entity/LightningBolt.java -index 2b09e9efad198ff596d88f97d703a8a00c108608..152ecd38814089333b8d61538297ce720756d2c3 100644 ---- a/src/main/java/net/minecraft/world/entity/LightningBolt.java -+++ b/src/main/java/net/minecraft/world/entity/LightningBolt.java -@@ -98,7 +98,7 @@ public class LightningBolt extends Entity { - } - - this.powerLightningRod(); -- LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition()); -+ LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition(), this); // Paper - Call EntityChangeBlockEvent - this.gameEvent(GameEvent.LIGHTNING_STRIKE); - } - } -@@ -202,7 +202,7 @@ public class LightningBolt extends Entity { - - } - -- private static void clearCopperOnLightningStrike(Level world, BlockPos pos) { -+ private static void clearCopperOnLightningStrike(Level world, BlockPos pos, Entity lightning) { // Paper - Call EntityChangeBlockEvent - BlockState iblockdata = world.getBlockState(pos); - BlockPos blockposition1; - BlockState iblockdata1; -@@ -216,24 +216,29 @@ public class LightningBolt extends Entity { - } - - if (iblockdata1.getBlock() instanceof WeatheringCopper) { -- world.setBlockAndUpdate(blockposition1, WeatheringCopper.getFirst(world.getBlockState(blockposition1))); -+ // Paper start - Call EntityChangeBlockEvent -+ BlockState newBlock = WeatheringCopper.getFirst(world.getBlockState(blockposition1)); -+ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1, newBlock)) { -+ world.setBlockAndUpdate(blockposition1, newBlock); -+ } -+ // Paper end - Call EntityChangeBlockEvent - BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); - int i = world.random.nextInt(3) + 3; - - for (int j = 0; j < i; ++j) { - int k = world.random.nextInt(8) + 1; - -- LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k); -+ LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - } - - } - } - -- private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count) { -+ private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - mutablePos.set(pos); - - for (int j = 0; j < count; ++j) { -- Optional optional = LightningBolt.randomStepCleaningCopper(world, mutablePos); -+ Optional optional = LightningBolt.randomStepCleaningCopper(world, mutablePos, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - - if (optional.isEmpty()) { - break; -@@ -244,7 +249,7 @@ public class LightningBolt extends Entity { - - } - -- private static Optional randomStepCleaningCopper(Level world, BlockPos pos) { -+ private static Optional randomStepCleaningCopper(Level world, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - Iterator iterator = BlockPos.randomInCube(world.random, 10, pos, 1).iterator(); - - BlockPos blockposition1; -@@ -261,6 +266,7 @@ public class LightningBolt extends Entity { - - BlockPos blockposition1Final = blockposition1; // CraftBukkit - decompile error - WeatheringCopper.getPrevious(iblockdata).ifPresent((iblockdata1) -> { -+ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1Final, iblockdata1)) // Paper - call EntityChangeBlockEvent - world.setBlockAndUpdate(blockposition1Final, iblockdata1); // CraftBukkit - decompile error - }); - world.levelEvent(3002, blockposition1, -1); -diff --git a/src/main/java/net/minecraft/world/item/AxeItem.java b/src/main/java/net/minecraft/world/item/AxeItem.java -index 74c9966093377b67e31b50483c2f24b70734faf6..abff08f2d61014944235ffe2f5494a718a28cc10 100644 ---- a/src/main/java/net/minecraft/world/item/AxeItem.java -+++ b/src/main/java/net/minecraft/world/item/AxeItem.java -@@ -67,6 +67,11 @@ public class AxeItem extends DiggerItem { - return InteractionResult.PASS; - } else { - ItemStack itemStack = context.getItemInHand(); -+ // Paper start - EntityChangeBlockEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, optional.get())) { -+ return InteractionResult.PASS; -+ } -+ // Paper end - if (player instanceof ServerPlayer) { - CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack); - } -diff --git a/src/main/java/net/minecraft/world/item/EnderEyeItem.java b/src/main/java/net/minecraft/world/item/EnderEyeItem.java -index 08cbf02bba3633a84cce90c202d13f2beb5b88a2..c71a426c47e0ebc57ecb8c9c1d171737a084ccab 100644 ---- a/src/main/java/net/minecraft/world/item/EnderEyeItem.java -+++ b/src/main/java/net/minecraft/world/item/EnderEyeItem.java -@@ -45,6 +45,11 @@ public class EnderEyeItem extends Item { - return InteractionResult.SUCCESS; - } else { - BlockState iblockdata1 = (BlockState) iblockdata.setValue(EndPortalFrameBlock.HAS_EYE, true); -+ // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockposition, iblockdata1)) { -+ return InteractionResult.PASS; -+ } -+ // Paper end - - Block.pushEntitiesUp(iblockdata, iblockdata1, world, blockposition); - world.setBlock(blockposition, iblockdata1, 2); -diff --git a/src/main/java/net/minecraft/world/item/HoneycombItem.java b/src/main/java/net/minecraft/world/item/HoneycombItem.java -index 6c0fe41692c9d1fa50a4f421eb4735860a9ae0e9..d7924825823b2bf79ca3a26272de11ff8d2ec74c 100644 ---- a/src/main/java/net/minecraft/world/item/HoneycombItem.java -+++ b/src/main/java/net/minecraft/world/item/HoneycombItem.java -@@ -74,6 +74,14 @@ public class HoneycombItem extends Item implements SignApplicator { - return getWaxed(blockState).map(state -> { - Player player = context.getPlayer(); - ItemStack itemStack = context.getItemInHand(); -+ // Paper start - EntityChangeBlockEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, state)) { -+ if (!player.isCreative()) { -+ player.containerMenu.sendAllDataToRemote(); -+ } -+ return InteractionResult.PASS; -+ } -+ // Paper end - if (player instanceof ServerPlayer serverPlayer) { - CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(serverPlayer, blockPos, itemStack); - } -diff --git a/src/main/java/net/minecraft/world/item/PotionItem.java b/src/main/java/net/minecraft/world/item/PotionItem.java -index 1c8fd643c32226d72d51abc869a49e256dd2432b..f19bd2c25d3c84d9f16cad38ac5c32736f0f3a8d 100644 ---- a/src/main/java/net/minecraft/world/item/PotionItem.java -+++ b/src/main/java/net/minecraft/world/item/PotionItem.java -@@ -42,6 +42,12 @@ public class PotionItem extends Item { - PotionContents potionContents = itemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); - BlockState blockState = level.getBlockState(blockPos); - if (context.getClickedFace() != Direction.DOWN && blockState.is(BlockTags.CONVERTABLE_TO_MUD) && potionContents.is(Potions.WATER)) { -+ // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, Blocks.MUD.defaultBlockState())) { -+ player.containerMenu.sendAllDataToRemote(); -+ return InteractionResult.PASS; -+ } -+ // Paper end - level.playSound(null, blockPos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F); - player.setItemInHand(context.getHand(), ItemUtils.createFilledResult(itemStack, player, new ItemStack(Items.GLASS_BOTTLE))); - player.awardStat(Stats.ITEM_USED.get(itemStack.getItem())); -diff --git a/src/main/java/net/minecraft/world/item/ShovelItem.java b/src/main/java/net/minecraft/world/item/ShovelItem.java -index c0377341227e8f4f1f7b1448580b3c7bc1b65f48..55c18f182166f4905d623d6f5e909eefd5ed2483 100644 ---- a/src/main/java/net/minecraft/world/item/ShovelItem.java -+++ b/src/main/java/net/minecraft/world/item/ShovelItem.java -@@ -46,20 +46,29 @@ public class ShovelItem extends DiggerItem { - Player player = context.getPlayer(); - BlockState blockState2 = FLATTENABLES.get(blockState.getBlock()); - BlockState blockState3 = null; -+ Runnable afterAction = null; // Paper - if (blockState2 != null && level.getBlockState(blockPos.above()).isAir()) { -- level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); -+ afterAction = () -> level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper - blockState3 = blockState2; - } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { -+ afterAction = () -> { // Paper - if (!level.isClientSide()) { - level.levelEvent(null, 1009, blockPos, 0); - } - - CampfireBlock.dowse(context.getPlayer(), level, blockPos, blockState); -+ }; // Paper - blockState3 = blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false)); - } - - if (blockState3 != null) { - if (!level.isClientSide) { -+ // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockPos, blockState3)) { -+ return InteractionResult.PASS; -+ } -+ afterAction.run(); -+ // Paper end - level.setBlock(blockPos, blockState3, 11); - level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, blockState3)); - if (player != null) { -diff --git a/src/main/java/net/minecraft/world/level/block/CakeBlock.java b/src/main/java/net/minecraft/world/level/block/CakeBlock.java -index 7629b9212ded7155e94f67ca429f62271e5f5aa0..648c2510beb162e73aed236a3169d0bbb8fc5050 100644 ---- a/src/main/java/net/minecraft/world/level/block/CakeBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CakeBlock.java -@@ -66,6 +66,12 @@ public class CakeBlock extends Block { - if (block instanceof CandleBlock) { - CandleBlock candleblock = (CandleBlock) block; - -+ // Paper start - call change block event -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, CandleCakeBlock.byCandle(candleblock))) { -+ player.containerMenu.sendAllDataToRemote(); // update inv because candle could decrease -+ return InteractionResult.TRY_WITH_EMPTY_HAND; -+ } -+ // Paper end - call change block event - stack.consume(1, player); - world.playSound((Player) null, pos, SoundEvents.CAKE_ADD_CANDLE, SoundSource.BLOCKS, 1.0F, 1.0F); - world.setBlockAndUpdate(pos, CandleCakeBlock.byCandle(candleblock)); -@@ -97,6 +103,14 @@ public class CakeBlock extends Block { - if (!player.canEat(false)) { - return InteractionResult.PASS; - } else { -+ // Paper start - call change block event -+ int i = state.getValue(CakeBlock.BITES); -+ final BlockState newState = i < MAX_BITES ? state.setValue(CakeBlock.BITES, i + 1) : world.getFluidState(pos).createLegacyBlock(); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) { -+ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); -+ return InteractionResult.PASS; // return a non-consume result to cake blocks don't drop their candles -+ } -+ // Paper end - call change block event - player.awardStat(Stats.EAT_CAKE_SLICE); - // CraftBukkit start - // entityhuman.getFoodData().eat(2, 0.1F); -@@ -110,7 +124,7 @@ public class CakeBlock extends Block { - - ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); - // CraftBukkit end -- int i = (Integer) state.getValue(CakeBlock.BITES); -+ // Paper - move up - - world.gameEvent((Entity) player, (Holder) GameEvent.EAT, pos); - if (i < 6) { -diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -index 2bcd246a26dad560cf69682b29983d320ebf1884..05b2eab26e2dc8e143e9fff2dcec40cfe927a197 100644 ---- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -@@ -243,6 +243,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - if (i < 8 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) { - if (i < 7 && !world.isClientSide) { - BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack); -+ // Paper start - handle cancelled events -+ if (iblockdata1 == null) { -+ return InteractionResult.PASS; -+ } -+ // Paper end - - world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0); - player.awardStat(Stats.ITEM_USED.get(stack.getItem())); -@@ -273,11 +278,16 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - if (i < 7 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) { - // CraftBukkit start - double rand = world.getRandom().nextDouble(); -- BlockState iblockdata1 = ComposterBlock.addItem(user, state, DummyGeneratorAccess.INSTANCE, pos, stack, rand); -- if (state == iblockdata1 || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(user, pos, iblockdata1)) { -+ BlockState iblockdata1 = null; // Paper -+ if (false && (state == iblockdata1 || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(user, pos, iblockdata1))) { // Paper - move event call into addItem - return state; - } - iblockdata1 = ComposterBlock.addItem(user, state, world, pos, stack, rand); -+ // Paper start - handle cancelled events -+ if (iblockdata1 == null) { -+ return state; -+ } -+ // Paper end - // CraftBukkit end - - stack.shrink(1); -@@ -318,11 +328,13 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - return iblockdata1; - } - -+ @Nullable // Paper - static BlockState addItem(@Nullable Entity user, BlockState state, LevelAccessor world, BlockPos pos, ItemStack stack) { - // CraftBukkit start - return ComposterBlock.addItem(user, state, world, pos, stack, world.getRandom().nextDouble()); - } - -+ @Nullable // Paper - make it nullable - static BlockState addItem(@Nullable Entity entity, BlockState iblockdata, LevelAccessor generatoraccess, BlockPos blockposition, ItemStack itemstack, double rand) { - // CraftBukkit end - int i = (Integer) iblockdata.getValue(ComposterBlock.LEVEL); -@@ -333,6 +345,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - } else { - int j = i + 1; - BlockState iblockdata1 = (BlockState) iblockdata.setValue(ComposterBlock.LEVEL, j); -+ // Paper start - move the EntityChangeBlockEvent here to avoid conflict later for the compost events -+ if (entity != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, iblockdata1)) { -+ return null; -+ } -+ // Paper end - - generatoraccess.setBlock(blockposition, iblockdata1, 3); - generatoraccess.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entity, iblockdata1)); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index 8224d5bddb7f7893dee09222a673af54791abcfa..f8828dc8334af19d7b2118e8cf34d94be5e09ee8 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -260,7 +260,13 @@ public class BeehiveBlockEntity extends BlockEntity { - --j; - } - -- world.setBlockAndUpdate(blockposition, (BlockState) iblockdata.setValue(BeehiveBlock.HONEY_LEVEL, i + j)); -+ // Paper start - Fire EntityChangeBlockEvent in more places -+ BlockState newBlockState = iblockdata.setValue(BeehiveBlock.HONEY_LEVEL, i + j); -+ -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entitybee, blockposition, newBlockState)) { -+ world.setBlockAndUpdate(blockposition, newBlockState); -+ } -+ // Paper end - Fire EntityChangeBlockEvent in more places - } - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -index daf3c26fce7569761951bfd5594c6726d854a9ff..e8a73d34dbb372581b03018aade170a31c266099 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -@@ -120,7 +120,7 @@ public class DummyGeneratorAccess implements WorldGenLevel { - - @Override - public void gameEvent(Holder event, Vec3 emitterPos, GameEvent.Context emitter) { -- // Used by BlockComposter -+ // Used by ComposterBlock - } - - @Override diff --git a/patches/server/0730-Missing-eating-regain-reason.patch b/patches/server/0730-Missing-eating-regain-reason.patch new file mode 100644 index 0000000000..38626b6352 --- /dev/null +++ b/patches/server/0730-Missing-eating-regain-reason.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Fri, 5 Aug 2022 12:16:51 +0200 +Subject: [PATCH] Missing eating regain reason + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java +index bffc7c21727a6e5ff13a498aa51f6797e4d6d596..471d5727b964922d8e898be9e1d5c30f9d3bac97 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java +@@ -407,7 +407,7 @@ public class Cat extends TamableAnimal implements VariantHolder 0.0F) { +- this.heal(f); ++ this.heal(f, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason + flag = true; + } + diff --git a/patches/server/0731-Missing-eating-regain-reason.patch b/patches/server/0731-Missing-eating-regain-reason.patch deleted file mode 100644 index 38626b6352..0000000000 --- a/patches/server/0731-Missing-eating-regain-reason.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Fri, 5 Aug 2022 12:16:51 +0200 -Subject: [PATCH] Missing eating regain reason - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index bffc7c21727a6e5ff13a498aa51f6797e4d6d596..471d5727b964922d8e898be9e1d5c30f9d3bac97 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -407,7 +407,7 @@ public class Cat extends TamableAnimal implements VariantHolder 0.0F) { -- this.heal(f); -+ this.heal(f, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason - flag = true; - } - diff --git a/patches/server/0731-Missing-effect-cause.patch b/patches/server/0731-Missing-effect-cause.patch new file mode 100644 index 0000000000..6157121022 --- /dev/null +++ b/patches/server/0731-Missing-effect-cause.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Tue, 16 Aug 2022 19:44:55 +0200 +Subject: [PATCH] Missing effect cause + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java +index 068d96cd0bceec79f14fbf3289eeb81533d1ba22..31b10cd404b672d7ce21c2107d8f83e32de26ef4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java ++++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java +@@ -424,7 +424,7 @@ public class Axolotl extends Animal implements VariantHolder, B + player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit + } + +- player.removeEffect(MobEffects.DIG_SLOWDOWN); ++ player.removeEffect(MobEffects.DIG_SLOWDOWN, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // Paper - Add missing effect cause + } + + @Override diff --git a/patches/server/0732-Added-byte-array-serialization-deserialization-for-P.patch b/patches/server/0732-Added-byte-array-serialization-deserialization-for-P.patch new file mode 100644 index 0000000000..f2a4d437f0 --- /dev/null +++ b/patches/server/0732-Added-byte-array-serialization-deserialization-for-P.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nex +Date: Thu, 24 Feb 2022 16:28:07 +0100 +Subject: [PATCH] Added byte array serialization/deserialization for + PersistentDataContainers + + +diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java +index 984e988a47aa55a3fd92198e379d0f92f511daef..5a4e7e7150b7c137b077e0b393f17ed35b5aec34 100644 +--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java ++++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java +@@ -184,4 +184,27 @@ public class CraftPersistentDataContainer implements PersistentDataContainer { + this.customDataTags.clear(); + } + // Paper end ++ ++ // Paper start - byte array serialization ++ @Override ++ public byte[] serializeToBytes() throws java.io.IOException { ++ final net.minecraft.nbt.CompoundTag root = this.toTagCompound(); ++ final java.io.ByteArrayOutputStream byteArrayOutput = new java.io.ByteArrayOutputStream(); ++ try (final java.io.DataOutputStream dataOutput = new java.io.DataOutputStream(byteArrayOutput)) { ++ net.minecraft.nbt.NbtIo.write(root, dataOutput); ++ return byteArrayOutput.toByteArray(); ++ } ++ } ++ ++ @Override ++ public void readFromBytes(final byte[] bytes, final boolean clear) throws java.io.IOException { ++ if (clear) { ++ this.clear(); ++ } ++ try (final java.io.DataInputStream dataInput = new java.io.DataInputStream(new java.io.ByteArrayInputStream(bytes))) { ++ final net.minecraft.nbt.CompoundTag compound = net.minecraft.nbt.NbtIo.read(dataInput); ++ this.putAll(compound); ++ } ++ } ++ // Paper end - byte array serialization + } diff --git a/patches/server/0732-Missing-effect-cause.patch b/patches/server/0732-Missing-effect-cause.patch deleted file mode 100644 index 6157121022..0000000000 --- a/patches/server/0732-Missing-effect-cause.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Tue, 16 Aug 2022 19:44:55 +0200 -Subject: [PATCH] Missing effect cause - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -index 068d96cd0bceec79f14fbf3289eeb81533d1ba22..31b10cd404b672d7ce21c2107d8f83e32de26ef4 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -+++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -424,7 +424,7 @@ public class Axolotl extends Animal implements VariantHolder, B - player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit - } - -- player.removeEffect(MobEffects.DIG_SLOWDOWN); -+ player.removeEffect(MobEffects.DIG_SLOWDOWN, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // Paper - Add missing effect cause - } - - @Override diff --git a/patches/server/0733-Added-byte-array-serialization-deserialization-for-P.patch b/patches/server/0733-Added-byte-array-serialization-deserialization-for-P.patch deleted file mode 100644 index f2a4d437f0..0000000000 --- a/patches/server/0733-Added-byte-array-serialization-deserialization-for-P.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nex -Date: Thu, 24 Feb 2022 16:28:07 +0100 -Subject: [PATCH] Added byte array serialization/deserialization for - PersistentDataContainers - - -diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -index 984e988a47aa55a3fd92198e379d0f92f511daef..5a4e7e7150b7c137b077e0b393f17ed35b5aec34 100644 ---- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -@@ -184,4 +184,27 @@ public class CraftPersistentDataContainer implements PersistentDataContainer { - this.customDataTags.clear(); - } - // Paper end -+ -+ // Paper start - byte array serialization -+ @Override -+ public byte[] serializeToBytes() throws java.io.IOException { -+ final net.minecraft.nbt.CompoundTag root = this.toTagCompound(); -+ final java.io.ByteArrayOutputStream byteArrayOutput = new java.io.ByteArrayOutputStream(); -+ try (final java.io.DataOutputStream dataOutput = new java.io.DataOutputStream(byteArrayOutput)) { -+ net.minecraft.nbt.NbtIo.write(root, dataOutput); -+ return byteArrayOutput.toByteArray(); -+ } -+ } -+ -+ @Override -+ public void readFromBytes(final byte[] bytes, final boolean clear) throws java.io.IOException { -+ if (clear) { -+ this.clear(); -+ } -+ try (final java.io.DataInputStream dataInput = new java.io.DataInputStream(new java.io.ByteArrayInputStream(bytes))) { -+ final net.minecraft.nbt.CompoundTag compound = net.minecraft.nbt.NbtIo.read(dataInput); -+ this.putAll(compound); -+ } -+ } -+ // Paper end - byte array serialization - } diff --git a/patches/server/0733-Call-BlockPhysicsEvent-more-often.patch b/patches/server/0733-Call-BlockPhysicsEvent-more-often.patch new file mode 100644 index 0000000000..ad24091f87 --- /dev/null +++ b/patches/server/0733-Call-BlockPhysicsEvent-more-often.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sun, 7 Aug 2022 22:16:36 +0200 +Subject: [PATCH] Call BlockPhysicsEvent more often + + +diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +index 5821c802ec880501df025fcd3fbbd98242ed952c..0587f4e5083a6c890a11642284a9c16fb2eb2fe1 100644 +--- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java ++++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +@@ -135,7 +135,20 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + orientation = this.orientation.withFront(direction); + } + +- NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false); ++ // Paper start - Call BlockPhysicsEvent ++ try { ++ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(world, blockPos), ++ org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(blockState), ++ org.bukkit.craftbukkit.block.CraftBlock.at(world, this.sourcePos)); ++ ++ if (event.callEvent()) { // continue to check for adjacent block (increase idx) ++ NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false); ++ } ++ } catch (StackOverflowError ex) { ++ world.lastPhysicsProblem = blockPos; ++ } ++ // Paper end - Call BlockPhysicsEvent + if (this.idx < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.idx] == this.skipDirection) { + this.idx++; + } diff --git a/patches/server/0734-Call-BlockPhysicsEvent-more-often.patch b/patches/server/0734-Call-BlockPhysicsEvent-more-often.patch deleted file mode 100644 index ad24091f87..0000000000 --- a/patches/server/0734-Call-BlockPhysicsEvent-more-often.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Sun, 7 Aug 2022 22:16:36 +0200 -Subject: [PATCH] Call BlockPhysicsEvent more often - - -diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -index 5821c802ec880501df025fcd3fbbd98242ed952c..0587f4e5083a6c890a11642284a9c16fb2eb2fe1 100644 ---- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -+++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -@@ -135,7 +135,20 @@ public class CollectingNeighborUpdater implements NeighborUpdater { - orientation = this.orientation.withFront(direction); - } - -- NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false); -+ // Paper start - Call BlockPhysicsEvent -+ try { -+ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(world, blockPos), -+ org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(blockState), -+ org.bukkit.craftbukkit.block.CraftBlock.at(world, this.sourcePos)); -+ -+ if (event.callEvent()) { // continue to check for adjacent block (increase idx) -+ NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false); -+ } -+ } catch (StackOverflowError ex) { -+ world.lastPhysicsProblem = blockPos; -+ } -+ // Paper end - Call BlockPhysicsEvent - if (this.idx < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.idx] == this.skipDirection) { - this.idx++; - } diff --git a/patches/server/0734-Configurable-chat-thread-limit.patch b/patches/server/0734-Configurable-chat-thread-limit.patch new file mode 100644 index 0000000000..a02e95e2bf --- /dev/null +++ b/patches/server/0734-Configurable-chat-thread-limit.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sun, 18 Sep 2022 06:33:17 +0100 +Subject: [PATCH] Configurable chat thread limit + +By default, spigot shifts chat over to an unbounded thread pool, +on a normal server, this really offers no gains, the creation of a thread +on submitting to the pool on these servers eats more time vs just running it in +the netty pipeline, however, on servers using plugins which do work in here, there +could be some overall benefits to moving this stuff outside of the pipeline. + +In general, this patch does two things: +1) Exposes the core size for the pool, this allows for ensuring that a number of threads +sit around in the pool, mitigating the need for creating new threads; This IS however +caveated, the ThreadPoolExecutor will ONLY create core threads as they're needed, it +just won't allow for us to dip back under the # of core threads, this can potentially +be mitigated by calling prestartCoreThread, however, I'm not sure if there is much justification +for this +2) Exposes a max size for the pool, as stated, by default this is unbounded, for most +servers limiting the size of the pool is going to have 0 effects given how fast chat +is actually processed, this is honestly really just exposed for the misnomers or people +who just wanna ensure that this won't grow over a specific size if chat gets stupidly active + +diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +index c3fe4481dd35f80815716e48beeeb07b1f51e30b..56798215644d8bca1695856b3a941e8089f49e48 100644 +--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java ++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +@@ -302,7 +302,18 @@ public class GlobalConfiguration extends ConfigurationPart { + + @PostProcess + private void postProcess() { +- // TODO: fill in separate patch ++ //noinspection ConstantConditions ++ if (net.minecraft.server.MinecraftServer.getServer() == null) return; // In testing env, this will be null here ++ int _chatExecutorMaxSize = (this.chatExecutorMaxSize <= 0) ? Integer.MAX_VALUE : this.chatExecutorMaxSize; // This is somewhat dumb, but, this is the default, do we cap this?; ++ int _chatExecutorCoreSize = Math.max(this.chatExecutorCoreSize, 0); ++ ++ if (_chatExecutorMaxSize < _chatExecutorCoreSize) { ++ _chatExecutorMaxSize = _chatExecutorCoreSize; ++ } ++ ++ java.util.concurrent.ThreadPoolExecutor executor = (java.util.concurrent.ThreadPoolExecutor) net.minecraft.server.MinecraftServer.getServer().chatExecutor; ++ executor.setCorePoolSize(_chatExecutorCoreSize); ++ executor.setMaximumPoolSize(_chatExecutorMaxSize); + } + } + public int maxJoinsPerTick = 5; diff --git a/patches/server/0735-Configurable-chat-thread-limit.patch b/patches/server/0735-Configurable-chat-thread-limit.patch deleted file mode 100644 index 1432c06594..0000000000 --- a/patches/server/0735-Configurable-chat-thread-limit.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 18 Sep 2022 06:33:17 +0100 -Subject: [PATCH] Configurable chat thread limit - -By default, spigot shifts chat over to an unbounded thread pool, -on a normal server, this really offers no gains, the creation of a thread -on submitting to the pool on these servers eats more time vs just running it in -the netty pipeline, however, on servers using plugins which do work in here, there -could be some overall benefits to moving this stuff outside of the pipeline. - -In general, this patch does two things: -1) Exposes the core size for the pool, this allows for ensuring that a number of threads -sit around in the pool, mitigating the need for creating new threads; This IS however -caveated, the ThreadPoolExecutor will ONLY create core threads as they're needed, it -just won't allow for us to dip back under the # of core threads, this can potentially -be mitigated by calling prestartCoreThread, however, I'm not sure if there is much justification -for this -2) Exposes a max size for the pool, as stated, by default this is unbounded, for most -servers limiting the size of the pool is going to have 0 effects given how fast chat -is actually processed, this is honestly really just exposed for the misnomers or people -who just wanna ensure that this won't grow over a specific size if chat gets stupidly active - -diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index 904d2f96a60e72aa089fdfe6be08044b04f995c1..36b96e0ed5c0d25068ec4678eddd8a19a020d345 100644 ---- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -327,7 +327,18 @@ public class GlobalConfiguration extends ConfigurationPart { - - @PostProcess - private void postProcess() { -- // TODO: fill in separate patch -+ //noinspection ConstantConditions -+ if (net.minecraft.server.MinecraftServer.getServer() == null) return; // In testing env, this will be null here -+ int _chatExecutorMaxSize = (this.chatExecutorMaxSize <= 0) ? Integer.MAX_VALUE : this.chatExecutorMaxSize; // This is somewhat dumb, but, this is the default, do we cap this?; -+ int _chatExecutorCoreSize = Math.max(this.chatExecutorCoreSize, 0); -+ -+ if (_chatExecutorMaxSize < _chatExecutorCoreSize) { -+ _chatExecutorMaxSize = _chatExecutorCoreSize; -+ } -+ -+ java.util.concurrent.ThreadPoolExecutor executor = (java.util.concurrent.ThreadPoolExecutor) net.minecraft.server.MinecraftServer.getServer().chatExecutor; -+ executor.setCorePoolSize(_chatExecutorCoreSize); -+ executor.setMaximumPoolSize(_chatExecutorMaxSize); - } - } - public int maxJoinsPerTick = 5; diff --git a/patches/server/0735-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch b/patches/server/0735-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch new file mode 100644 index 0000000000..fb6e8b07ea --- /dev/null +++ b/patches/server/0735-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Mon, 19 Sep 2022 00:13:02 +0100 +Subject: [PATCH] Mitigate effects of WorldCreator#keepSpawnLoaded ret type + change + +TODO: Remove in 1.21? + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +index 63d4ffe93a445abf3c766d4f1f8fbf4a412a2a03..419b899f0e65b9656432513b69f60150c75bd13f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +@@ -458,6 +458,12 @@ public class Commodore { + super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, runtimeCbPkgPrefix() + "advancement/CraftAdvancement", "getDisplay0", desc, false); + return; + } ++ if (owner.equals("org/bukkit/WorldCreator") && name.equals("keepSpawnLoaded") && desc.equals("(Lnet/kyori/adventure/util/TriState;)V")) { ++ super.visitMethodInsn(opcode, owner, name, "(Lnet/kyori/adventure/util/TriState;)Lorg/bukkit/WorldCreator;", itf); ++ // new method has a return, so, make sure we pop it ++ super.visitInsn(Opcodes.POP); ++ return; ++ } + // Paper end + + // Paper start - ItemFactory#getSpawnEgg (paper had original method that returned ItemStack, upstream added identical but returned Material) diff --git a/patches/server/0736-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch b/patches/server/0736-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch deleted file mode 100644 index fb6e8b07ea..0000000000 --- a/patches/server/0736-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Mon, 19 Sep 2022 00:13:02 +0100 -Subject: [PATCH] Mitigate effects of WorldCreator#keepSpawnLoaded ret type - change - -TODO: Remove in 1.21? - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -index 63d4ffe93a445abf3c766d4f1f8fbf4a412a2a03..419b899f0e65b9656432513b69f60150c75bd13f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -@@ -458,6 +458,12 @@ public class Commodore { - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, runtimeCbPkgPrefix() + "advancement/CraftAdvancement", "getDisplay0", desc, false); - return; - } -+ if (owner.equals("org/bukkit/WorldCreator") && name.equals("keepSpawnLoaded") && desc.equals("(Lnet/kyori/adventure/util/TriState;)V")) { -+ super.visitMethodInsn(opcode, owner, name, "(Lnet/kyori/adventure/util/TriState;)Lorg/bukkit/WorldCreator;", itf); -+ // new method has a return, so, make sure we pop it -+ super.visitInsn(Opcodes.POP); -+ return; -+ } - // Paper end - - // Paper start - ItemFactory#getSpawnEgg (paper had original method that returned ItemStack, upstream added identical but returned Material) diff --git a/patches/server/0736-fix-Jigsaw-block-kicking-user.patch b/patches/server/0736-fix-Jigsaw-block-kicking-user.patch new file mode 100644 index 0000000000..749d498f57 --- /dev/null +++ b/patches/server/0736-fix-Jigsaw-block-kicking-user.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Legitimoose +Date: Wed, 28 Sep 2022 22:45:49 -0700 +Subject: [PATCH] fix Jigsaw block kicking user + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java +index 42300114e3baf31fd26090fca3b497c8157d4bb9..6410cd7a7324bb04e9285a5b090b1675a5ffa16f 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java +@@ -131,7 +131,12 @@ public class JigsawBlockEntity extends BlockEntity { + public void generate(ServerLevel world, int maxDepth, boolean keepJigsaws) { + BlockPos blockPos = this.getBlockPos().relative(this.getBlockState().getValue(JigsawBlock.ORIENTATION).front()); + Registry registry = world.registryAccess().lookupOrThrow(Registries.TEMPLATE_POOL); +- Holder holder = registry.getOrThrow(this.pool); ++ // Paper start - Replace getHolderOrThrow with a null check ++ Holder holder = registry.get(this.pool).orElse(null); ++ if (holder == null) { ++ return; ++ } ++ // Paper end - Replace getHolderOrThrow with a null check + JigsawPlacement.generateJigsaw(world, holder, this.target, maxDepth, blockPos, keepJigsaws); + } + diff --git a/patches/server/0737-fix-Jigsaw-block-kicking-user.patch b/patches/server/0737-fix-Jigsaw-block-kicking-user.patch deleted file mode 100644 index 749d498f57..0000000000 --- a/patches/server/0737-fix-Jigsaw-block-kicking-user.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Legitimoose -Date: Wed, 28 Sep 2022 22:45:49 -0700 -Subject: [PATCH] fix Jigsaw block kicking user - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java -index 42300114e3baf31fd26090fca3b497c8157d4bb9..6410cd7a7324bb04e9285a5b090b1675a5ffa16f 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/JigsawBlockEntity.java -@@ -131,7 +131,12 @@ public class JigsawBlockEntity extends BlockEntity { - public void generate(ServerLevel world, int maxDepth, boolean keepJigsaws) { - BlockPos blockPos = this.getBlockPos().relative(this.getBlockState().getValue(JigsawBlock.ORIENTATION).front()); - Registry registry = world.registryAccess().lookupOrThrow(Registries.TEMPLATE_POOL); -- Holder holder = registry.getOrThrow(this.pool); -+ // Paper start - Replace getHolderOrThrow with a null check -+ Holder holder = registry.get(this.pool).orElse(null); -+ if (holder == null) { -+ return; -+ } -+ // Paper end - Replace getHolderOrThrow with a null check - JigsawPlacement.generateJigsaw(world, holder, this.target, maxDepth, blockPos, keepJigsaws); - } - diff --git a/patches/server/0737-use-BlockFormEvent-for-mud-converting-into-clay.patch b/patches/server/0737-use-BlockFormEvent-for-mud-converting-into-clay.patch new file mode 100644 index 0000000000..3159c4b594 --- /dev/null +++ b/patches/server/0737-use-BlockFormEvent-for-mud-converting-into-clay.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Legitimoose +Date: Thu, 29 Sep 2022 16:25:50 -0700 +Subject: [PATCH] use BlockFormEvent for mud converting into clay + + +diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java +index bd38a0a73d543a85bb5c6d50219f5438ce194df3..53cea36ec931de89e0060613acf87beb51dc16ec 100644 +--- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java +@@ -219,10 +219,13 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate + if (((PointedDripstoneBlock.FluidInfo) optional.get()).sourceState.is(Blocks.MUD) && fluidtype == Fluids.WATER) { + BlockState iblockdata1 = Blocks.CLAY.defaultBlockState(); + +- world.setBlockAndUpdate(((PointedDripstoneBlock.FluidInfo) optional.get()).pos, iblockdata1); ++ // Paper start - Call BlockFormEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(world, ((PointedDripstoneBlock.FluidInfo) optional.get()).pos, iblockdata1)) { + Block.pushEntitiesUp(((PointedDripstoneBlock.FluidInfo) optional.get()).sourceState, iblockdata1, world, ((PointedDripstoneBlock.FluidInfo) optional.get()).pos); + world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, ((PointedDripstoneBlock.FluidInfo) optional.get()).pos, GameEvent.Context.of(iblockdata1)); + world.levelEvent(1504, blockposition1, 0); ++ } ++ // Paper end - Call BlockFormEvent + } else { + BlockPos blockposition2 = PointedDripstoneBlock.findFillableCauldronBelowStalactiteTip(world, blockposition1, fluidtype); + diff --git a/patches/server/0738-Add-getDrops-to-BlockState.patch b/patches/server/0738-Add-getDrops-to-BlockState.patch new file mode 100644 index 0000000000..ea12f69bde --- /dev/null +++ b/patches/server/0738-Add-getDrops-to-BlockState.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MelnCat +Date: Fri, 12 Aug 2022 23:24:37 -0700 +Subject: [PATCH] Add getDrops to BlockState + +Originally added isPreferredTool to BlockData but +upstream added that. + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +index e96023b71845526383288917e8d7c5759a4c0e9b..fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +@@ -347,5 +347,24 @@ public class CraftBlockState implements BlockState { + public boolean isCollidable() { + return this.data.getBlock().hasCollision; + } ++ ++ @Override ++ public java.util.Collection getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) { ++ this.requirePlaced(); ++ net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item); ++ ++ // Modelled off EntityHuman#hasBlock ++ if (item == null || !data.requiresCorrectToolForDrops() || nms.isCorrectToolForDrops(data)) { ++ return net.minecraft.world.level.block.Block.getDrops( ++ data, ++ world.getHandle(), ++ position, ++ world.getHandle().getBlockEntity(position), entity == null ? null : ++ ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle(), nms ++ ).stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asBukkitCopy).toList(); ++ } else { ++ return java.util.Collections.emptyList(); ++ } ++ } + // Paper end + } diff --git a/patches/server/0738-use-BlockFormEvent-for-mud-converting-into-clay.patch b/patches/server/0738-use-BlockFormEvent-for-mud-converting-into-clay.patch deleted file mode 100644 index 3159c4b594..0000000000 --- a/patches/server/0738-use-BlockFormEvent-for-mud-converting-into-clay.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Legitimoose -Date: Thu, 29 Sep 2022 16:25:50 -0700 -Subject: [PATCH] use BlockFormEvent for mud converting into clay - - -diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -index bd38a0a73d543a85bb5c6d50219f5438ce194df3..53cea36ec931de89e0060613acf87beb51dc16ec 100644 ---- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -@@ -219,10 +219,13 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate - if (((PointedDripstoneBlock.FluidInfo) optional.get()).sourceState.is(Blocks.MUD) && fluidtype == Fluids.WATER) { - BlockState iblockdata1 = Blocks.CLAY.defaultBlockState(); - -- world.setBlockAndUpdate(((PointedDripstoneBlock.FluidInfo) optional.get()).pos, iblockdata1); -+ // Paper start - Call BlockFormEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(world, ((PointedDripstoneBlock.FluidInfo) optional.get()).pos, iblockdata1)) { - Block.pushEntitiesUp(((PointedDripstoneBlock.FluidInfo) optional.get()).sourceState, iblockdata1, world, ((PointedDripstoneBlock.FluidInfo) optional.get()).pos); - world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, ((PointedDripstoneBlock.FluidInfo) optional.get()).pos, GameEvent.Context.of(iblockdata1)); - world.levelEvent(1504, blockposition1, 0); -+ } -+ // Paper end - Call BlockFormEvent - } else { - BlockPos blockposition2 = PointedDripstoneBlock.findFillableCauldronBelowStalactiteTip(world, blockposition1, fluidtype); - diff --git a/patches/server/0739-Add-getDrops-to-BlockState.patch b/patches/server/0739-Add-getDrops-to-BlockState.patch deleted file mode 100644 index ea12f69bde..0000000000 --- a/patches/server/0739-Add-getDrops-to-BlockState.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Fri, 12 Aug 2022 23:24:37 -0700 -Subject: [PATCH] Add getDrops to BlockState - -Originally added isPreferredTool to BlockData but -upstream added that. - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -index e96023b71845526383288917e8d7c5759a4c0e9b..fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -@@ -347,5 +347,24 @@ public class CraftBlockState implements BlockState { - public boolean isCollidable() { - return this.data.getBlock().hasCollision; - } -+ -+ @Override -+ public java.util.Collection getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) { -+ this.requirePlaced(); -+ net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item); -+ -+ // Modelled off EntityHuman#hasBlock -+ if (item == null || !data.requiresCorrectToolForDrops() || nms.isCorrectToolForDrops(data)) { -+ return net.minecraft.world.level.block.Block.getDrops( -+ data, -+ world.getHandle(), -+ position, -+ world.getHandle().getBlockEntity(position), entity == null ? null : -+ ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle(), nms -+ ).stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asBukkitCopy).toList(); -+ } else { -+ return java.util.Collections.emptyList(); -+ } -+ } - // Paper end - } diff --git a/patches/server/0739-Fix-a-bunch-of-vanilla-bugs.patch b/patches/server/0739-Fix-a-bunch-of-vanilla-bugs.patch new file mode 100644 index 0000000000..93ef32db8a --- /dev/null +++ b/patches/server/0739-Fix-a-bunch-of-vanilla-bugs.patch @@ -0,0 +1,394 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 11 Jul 2022 11:56:41 -0700 +Subject: [PATCH] Fix a bunch of vanilla bugs + +https://bugs.mojang.com/browse/MC-253721 + wrong msg for opping multiple players + +https://bugs.mojang.com/browse/MC-248588 + respect mob griefing gamerule for draining water cauldrons + +https://bugs.mojang.com/browse/MC-244739 + play goat eating sound for last item in stack + +https://bugs.mojang.com/browse/MC-243057 + ignore furnace fuel slot in recipe book click + +https://bugs.mojang.com/browse/MC-147659 + Some witch huts spawn the incorrect cat + Note: Marked as Won't Fix, makes 0 sense + +https://bugs.mojang.com/browse/MC-179072 + Creepers do not defuse when switching from Survival to Creative/Spectator + +https://bugs.mojang.com/browse/MC-259571 + Fix changeGameModeForPlayer to use gameModeForPlayer + +https://bugs.mojang.com/browse/MC-262422 + Fix lightning being able to hit spectators + +https://bugs.mojang.com/browse/MC-224454 + Fix mobs attempting to pathfind through azalea blocks + +https://bugs.mojang.com/browse/MC-263999 + Fix mobs breaking doors not spawning block break particles + +https://bugs.mojang.com/browse/MC-210802 + Fixes sheep eating blocks outside of ticking range + +https://bugs.mojang.com/browse/MC-123848 + Fixes item frames dropping items above when pointing down + +https://bugs.mojang.com/browse/MC-174630 + Fix secondary beacon effect remaining after switching effect + +https://bugs.mojang.com/browse/MC-153086 + Fix the beacon deactivation sound always playing when broken + +https://bugs.mojang.com/browse/MC-200092 + Fix yaw being ignored for a player's first spawn pos + +https://bugs.mojang.com/browse/MC-158900 + Fix error when joining after tempban expired + +https://bugs.mojang.com/browse/MC-99075 + Fix inventory desync within spawn protected area + +https://bugs.mojang.com/browse/MC-273635 + Fix TrialSpawner forgets assigned mob when placed by player + +== AT == +public net/minecraft/world/entity/Mob leashInfoTag + +Co-authored-by: William Blake Galbreath +Co-authored-by: Spottedleaf + +diff --git a/src/main/java/net/minecraft/server/commands/DeOpCommands.java b/src/main/java/net/minecraft/server/commands/DeOpCommands.java +index 0283f26151488d715dc823a0008c9a37ef6740fb..d98447e58233745665f0833196226077d972cc2a 100644 +--- a/src/main/java/net/minecraft/server/commands/DeOpCommands.java ++++ b/src/main/java/net/minecraft/server/commands/DeOpCommands.java +@@ -35,7 +35,7 @@ public class DeOpCommands { + if (playerList.isOp(gameProfile)) { + playerList.deop(gameProfile); + i++; +- source.sendSuccess(() -> Component.translatable("commands.deop.success", targets.iterator().next().getName()), true); ++ source.sendSuccess(() -> Component.translatable("commands.deop.success", gameProfile.getName()), true); // Paper - fixes MC-253721 + } + } + +diff --git a/src/main/java/net/minecraft/server/commands/OpCommand.java b/src/main/java/net/minecraft/server/commands/OpCommand.java +index 6854ca4d4fec2b4fa541c3fabf63787665572609..e7b444a10b244828827b3c66c53465206ea8e0ec 100644 +--- a/src/main/java/net/minecraft/server/commands/OpCommand.java ++++ b/src/main/java/net/minecraft/server/commands/OpCommand.java +@@ -46,7 +46,7 @@ public class OpCommand { + if (!playerList.isOp(gameProfile)) { + playerList.op(gameProfile); + i++; +- source.sendSuccess(() -> Component.translatable("commands.op.success", targets.iterator().next().getName()), true); ++ source.sendSuccess(() -> Component.translatable("commands.op.success", gameProfile.getName()), true); // Paper - fixes MC-253721 + } + } + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index b92a889d0b0c46c1fa247d770f303d7d37dfc36c..e1c69c3c8e4809c7ccd2e1e12ee8538ab4bd3d5c 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1078,7 +1078,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + } + +- boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) { ++ public boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) { // Paper - public + // Spigot start + return this.anyPlayerCloseEnoughForSpawning(pos, false); + } +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index f3f93e8cbc2a5c9d0a3841ec7de010477bfd976a..d01f42aad003c7b0ea5700d32109eed4a264fa4c 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -748,7 +748,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } else { + AABB axisalignedbb = AABB.encapsulatingFullBlocks(blockposition1, blockposition1.atY(this.getMaxY() + 1)).inflate(3.0D); + List list = this.getEntitiesOfClass(LivingEntity.class, axisalignedbb, (entityliving) -> { +- return entityliving != null && entityliving.isAlive() && this.canSeeSky(entityliving.blockPosition()); ++ return entityliving != null && entityliving.isAlive() && this.canSeeSky(entityliving.blockPosition()) && !entityliving.isSpectator(); // Paper - Fix lightning being able to hit spectators (MC-262422) + }); + + if (!list.isEmpty()) { +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 064a7a3e1c4d192010e072a5e985a54135748d87..a706f0855fdf88cc9aece3ba00ef574b9cd8bd11 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -91,7 +91,7 @@ public class ServerPlayerGameMode { + return event; // Paper - Expand PlayerGameModeChangeEvent + } + // CraftBukkit end +- this.setGameModeForPlayer(gameMode, this.previousGameModeForPlayer); ++ this.setGameModeForPlayer(gameMode, this.gameModeForPlayer); // Paper - Fix MC-259571 + this.player.onUpdateAbilities(); + this.player.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit + this.level.updateSleepingPlayerList(); +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index b48966424fb8e937552c0e7bffaedaefc63ef77f..79eceb995f92b3f3d7b695dc6d2a0a4a824ce871 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1831,7 +1831,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.player.swing(enumhand, true); + } + } +- } ++ } else { this.player.containerMenu.sendAllDataToRemote(); } // Paper - Fix inventory desync; MC-99075 + } else { + MutableComponent ichatmutablecomponent1 = Component.translatable("build.tooHigh", i).withStyle(ChatFormatting.RED); + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 3d741bd09cd2086aa63b77636fe3ecfc55577aad..6332d5e281bb355bee1a112d11e96ee26e337ebf 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -260,7 +260,7 @@ public abstract class PlayerList { + } + if (optional.isEmpty() || invalidPlayerWorld[0]) { + // Paper end - reset to main world spawn if first spawn or invalid world +- player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); ++ player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), worldserver1.getSharedSpawnAngle(), 0.0F); // Paper - MC-200092 - fix first spawn pos yaw being ignored + } + // Paper end - Entity#getEntitySpawnReason + player.setServerLevel(worldserver1); +@@ -660,8 +660,10 @@ public abstract class PlayerList { + Player player = entity.getBukkitEntity(); + PlayerLoginEvent event = new PlayerLoginEvent(player, loginlistener.connection.hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.connection.channel.remoteAddress()).getAddress()); + +- if (this.bans.isBanned(gameprofile)) { +- UserBanListEntry gameprofilebanentry = (UserBanListEntry) this.bans.get(gameprofile); ++ // Paper start - Fix MC-158900 ++ UserBanListEntry gameprofilebanentry; ++ if (this.bans.isBanned(gameprofile) && (gameprofilebanentry = this.bans.get(gameprofile)) != null) { ++ // Paper end - Fix MC-158900 + + ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason()); + if (gameprofilebanentry.getExpires() != null) { +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java +index 6827426e6e9706909265f84bf97b5fa7105a7fea..7324da6b7dd2623ce394e3827ff77ef684a3b98b 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java +@@ -78,9 +78,10 @@ public class BreakDoorGoal extends DoorInteractGoal { + return; + } + // CraftBukkit end ++ final net.minecraft.world.level.block.state.BlockState oldState = this.mob.level().getBlockState(this.doorPos); // Paper - fix MC-263999 + this.mob.level().removeBlock(this.doorPos, false); + this.mob.level().levelEvent(1021, this.doorPos, 0); +- this.mob.level().levelEvent(2001, this.doorPos, Block.getId(this.mob.level().getBlockState(this.doorPos))); ++ this.mob.level().levelEvent(2001, this.doorPos, Block.getId(oldState)); // Paper - fix MC-263999 + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java +index 9e6f946e6d2878aa3fa8abe0f6fa4770d18676d3..32bb591371fe78ba10a2bc52389ef33978cbc0eb 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java +@@ -31,6 +31,11 @@ public class EatBlockGoal extends Goal { + + @Override + public boolean canUse() { ++ // Paper start - Fix MC-210802 ++ if (!((net.minecraft.server.level.ServerLevel) this.level).chunkSource.chunkMap.anyPlayerCloseEnoughForSpawning(this.mob.chunkPosition())) { ++ return false; ++ } ++ // Paper end + if (this.mob.getRandom().nextInt(this.mob.isBaby() ? 50 : 1000) != 0) { + return false; + } else { +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java +index ef71b3ef4444c05b4211de87e1c8ec52cbe3e72a..137ec75ee803789deb7b1ca93dd9369c9af362b9 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java +@@ -21,6 +21,13 @@ public class SwellGoal extends Goal { + return this.creeper.getSwellDir() > 0 || livingEntity != null && this.creeper.distanceToSqr(livingEntity) < 9.0; + } + ++ // Paper start - Fix MC-179072 ++ @Override ++ public boolean canContinueToUse() { ++ return !net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(this.creeper.getTarget()) && canUse(); ++ } ++ // Paper end ++ + @Override + public void start() { + this.creeper.getNavigation().stop(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +index 14b47d6fa189f2a666b12ef7e7708d204c2b0452..4c6dc427b90012b0945e073dd905dc7e8d1bec82 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +@@ -247,9 +247,10 @@ public class Goat extends Animal { + player.setItemInHand(hand, itemstack1); + return InteractionResult.SUCCESS; + } else { ++ boolean isFood = this.isFood(itemstack); // Paper - track before stack is possibly decreased to 0 (Fixes MC-244739) + InteractionResult enuminteractionresult = super.mobInteract(player, hand); + +- if (enuminteractionresult.consumesAction() && this.isFood(itemstack)) { ++ if (enuminteractionresult.consumesAction() && isFood) { // Paper + this.playEatingSound(); + } + +diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java +index 30af4cbb17148c247a46c0346419d6c838dbc9d2..65f7f1f98f415a564aadb440d3a67143699e43db 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java +@@ -272,6 +272,14 @@ public class ItemFrame extends HangingEntity { + return (ItemStack) this.getEntityData().get(ItemFrame.DATA_ITEM); + } + ++ // Paper start - Fix MC-123848 (spawn item frame drops above block) ++ @Nullable ++ @Override ++ public net.minecraft.world.entity.item.ItemEntity spawnAtLocation(ServerLevel serverLevel, ItemStack stack) { ++ return this.spawnAtLocation(serverLevel, stack, getDirection().equals(Direction.DOWN) ? -0.6F : 0.0F); ++ } ++ // Paper end ++ + @Nullable + public MapId getFramedMapId(ItemStack stack) { + return (MapId) stack.get(DataComponents.MAP_ID); +diff --git a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java +index 15a1ea01917ce57c2457094186dde937c21ffb22..b0236c7bf9441aa84d3795ffed05dd6099f29636 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java ++++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java +@@ -82,8 +82,8 @@ public class CatSpawner implements CustomSpawner { + if (cat == null) { + return 0; + } else { ++ cat.moveTo(pos, 0.0F, 0.0F); // Paper - move up - Fix MC-147659 + cat.finalizeSpawn(world, world.getCurrentDifficultyAt(pos), EntitySpawnReason.NATURAL, null); +- cat.moveTo(pos, 0.0F, 0.0F); + world.addFreshEntityWithPassengers(cat); + return 1; + } +diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +index cad0b581c992edc5cd312a727695a443e26e96d8..9db647cfbd3f9c884465cf3d3a1b911d46a3da58 100644 +--- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +@@ -164,6 +164,11 @@ public class BeaconMenu extends AbstractContainerMenu { + // Paper end - Add PlayerChangeBeaconEffectEvent + + public void updateEffects(Optional> primary, Optional> secondary) { ++ // Paper start - fix MC-174630 - validate secondary power ++ if (secondary.isPresent() && secondary.get() != net.minecraft.world.effect.MobEffects.REGENERATION && (primary.isPresent() && secondary.get() != primary.get())) { ++ secondary = Optional.empty(); ++ } ++ // Paper end + if (this.paymentSlot.hasItem()) { + // Paper start - Add PlayerChangeBeaconEffectEvent + io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent event = new io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent((org.bukkit.entity.Player) this.player.player.getBukkitEntity(), convert(primary), convert(secondary), this.access.getLocation().getBlock()); +diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java +index 7dd6b7c0ea472cfbc7ece55bc64bc5d85be4a6c0..6dcb571e9f35fbae724be69dc113b0c33eca63b3 100644 +--- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java +@@ -72,7 +72,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { + if (entity.isOnFire() && this.isEntityInsideContent(state, pos, entity)) { + // CraftBukkit start - moved down + // entity.clearFire(); +- if (entity.mayInteract(worldserver, pos)) { ++ if ((entity instanceof net.minecraft.world.entity.player.Player || worldserver.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING)) && entity.mayInteract(worldserver, pos)) { // Paper - Fixes MC-248588 + if (this.handleEntityOnFireInsideWithEvent(state, world, pos, entity)) { // Paper - fix powdered snow cauldron extinguishing entities + entity.clearFire(); + } +diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +index 9c1267df7057caa3500c7a9e6c705ea58c2b5e11..4d36aa195332c2ff6fa7bc5fff61ff7dc80a3fd5 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +@@ -531,13 +531,10 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + + @Override + public void fillStackedContents(StackedItemContents finder) { +- Iterator iterator = this.items.iterator(); +- +- while (iterator.hasNext()) { +- ItemStack itemstack = (ItemStack) iterator.next(); +- +- finder.accountStack(itemstack); +- } ++ // Paper start - don't account fuel stack (fixes MC-243057) ++ finder.accountStack(this.items.get(SLOT_INPUT)); ++ finder.accountStack(this.items.get(SLOT_RESULT)); ++ // Paper end + + } + } +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +index 8aab6f68f576fb022eb59798585e264f5aafbc69..edd6017937a7f20a1b43fa15204ec130b524b52b 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +@@ -295,7 +295,11 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, worldPosition); + new io.papermc.paper.event.block.BeaconDeactivatedEvent(block).callEvent(); + // Paper end - beacon activation/deactivation events ++ // Paper start - fix MC-153086 ++ if (this.levels > 0 && !this.beamSections.isEmpty()) { + BeaconBlockEntity.playSound(this.level, this.worldPosition, SoundEvents.BEACON_DEACTIVATE); ++ } ++ // Paper end + super.setRemoved(); + } + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java +index e64a30577e9000e5c4d22fd3d9cf8a9381c5c459..b9690f31d410e82d833b2ca805df2fa68abcb6d1 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java +@@ -101,17 +101,19 @@ public class TrialSpawnerData { + this.ejectingLootTable = rewardLootTable; + } + +- public void reset() { ++ public void reset(TrialSpawner logic) { // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 + this.currentMobs.clear(); + this.nextSpawnData = Optional.empty(); +- this.resetStatistics(); ++ this.resetStatistics(logic); + } + +- public void resetStatistics() { ++ public void resetStatistics(TrialSpawner logic) { // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 + this.detectedPlayers.clear(); + this.totalMobsSpawned = 0; + this.nextMobSpawnsAt = 0L; + this.cooldownEndsAt = 0L; ++ this.nextSpawnData = Optional.empty(); ++ if (!logic.getConfig().spawnPotentialsDefinition().isEmpty()) this.nextSpawnData = Optional.empty(); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 + } + + public boolean hasMobToSpawn(TrialSpawner logic, RandomSource random) { +diff --git a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java +index 83cdeee5e2ce115ff696a5afc5465dc4301779b9..027d5c4117feba1e152d0ecf9923aef77ba72207 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java +@@ -68,7 +68,7 @@ public enum TrialSpawnerState implements StringRepresentable { + case INACTIVE -> trialSpawnerData.getOrCreateDisplayEntity(logic, world, WAITING_FOR_PLAYERS) == null ? this : WAITING_FOR_PLAYERS; + case WAITING_FOR_PLAYERS -> { + if (!logic.canSpawnInLevel(world)) { +- trialSpawnerData.resetStatistics(); ++ trialSpawnerData.resetStatistics(logic); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 + yield this; + } else if (!trialSpawnerData.hasMobToSpawn(logic, world.random)) { + yield INACTIVE; +@@ -79,7 +79,7 @@ public enum TrialSpawnerState implements StringRepresentable { + } + case ACTIVE -> { + if (!logic.canSpawnInLevel(world)) { +- trialSpawnerData.resetStatistics(); ++ trialSpawnerData.resetStatistics(logic); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 + yield WAITING_FOR_PLAYERS; + } else if (!trialSpawnerData.hasMobToSpawn(logic, world.random)) { + yield INACTIVE; +@@ -145,7 +145,7 @@ public enum TrialSpawnerState implements StringRepresentable { + yield ACTIVE; + } else if (trialSpawnerData.isCooldownFinished(world)) { + logic.removeOminous(world, pos); +- trialSpawnerData.reset(); ++ trialSpawnerData.reset(logic); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 + yield WAITING_FOR_PLAYERS; + } else { + yield this; diff --git a/patches/server/0740-Fix-a-bunch-of-vanilla-bugs.patch b/patches/server/0740-Fix-a-bunch-of-vanilla-bugs.patch deleted file mode 100644 index 69ca61a6dc..0000000000 --- a/patches/server/0740-Fix-a-bunch-of-vanilla-bugs.patch +++ /dev/null @@ -1,394 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 11 Jul 2022 11:56:41 -0700 -Subject: [PATCH] Fix a bunch of vanilla bugs - -https://bugs.mojang.com/browse/MC-253721 - wrong msg for opping multiple players - -https://bugs.mojang.com/browse/MC-248588 - respect mob griefing gamerule for draining water cauldrons - -https://bugs.mojang.com/browse/MC-244739 - play goat eating sound for last item in stack - -https://bugs.mojang.com/browse/MC-243057 - ignore furnace fuel slot in recipe book click - -https://bugs.mojang.com/browse/MC-147659 - Some witch huts spawn the incorrect cat - Note: Marked as Won't Fix, makes 0 sense - -https://bugs.mojang.com/browse/MC-179072 - Creepers do not defuse when switching from Survival to Creative/Spectator - -https://bugs.mojang.com/browse/MC-259571 - Fix changeGameModeForPlayer to use gameModeForPlayer - -https://bugs.mojang.com/browse/MC-262422 - Fix lightning being able to hit spectators - -https://bugs.mojang.com/browse/MC-224454 - Fix mobs attempting to pathfind through azalea blocks - -https://bugs.mojang.com/browse/MC-263999 - Fix mobs breaking doors not spawning block break particles - -https://bugs.mojang.com/browse/MC-210802 - Fixes sheep eating blocks outside of ticking range - -https://bugs.mojang.com/browse/MC-123848 - Fixes item frames dropping items above when pointing down - -https://bugs.mojang.com/browse/MC-174630 - Fix secondary beacon effect remaining after switching effect - -https://bugs.mojang.com/browse/MC-153086 - Fix the beacon deactivation sound always playing when broken - -https://bugs.mojang.com/browse/MC-200092 - Fix yaw being ignored for a player's first spawn pos - -https://bugs.mojang.com/browse/MC-158900 - Fix error when joining after tempban expired - -https://bugs.mojang.com/browse/MC-99075 - Fix inventory desync within spawn protected area - -https://bugs.mojang.com/browse/MC-273635 - Fix TrialSpawner forgets assigned mob when placed by player - -== AT == -public net/minecraft/world/entity/Mob leashInfoTag - -Co-authored-by: William Blake Galbreath -Co-authored-by: Spottedleaf - -diff --git a/src/main/java/net/minecraft/server/commands/DeOpCommands.java b/src/main/java/net/minecraft/server/commands/DeOpCommands.java -index 0283f26151488d715dc823a0008c9a37ef6740fb..d98447e58233745665f0833196226077d972cc2a 100644 ---- a/src/main/java/net/minecraft/server/commands/DeOpCommands.java -+++ b/src/main/java/net/minecraft/server/commands/DeOpCommands.java -@@ -35,7 +35,7 @@ public class DeOpCommands { - if (playerList.isOp(gameProfile)) { - playerList.deop(gameProfile); - i++; -- source.sendSuccess(() -> Component.translatable("commands.deop.success", targets.iterator().next().getName()), true); -+ source.sendSuccess(() -> Component.translatable("commands.deop.success", gameProfile.getName()), true); // Paper - fixes MC-253721 - } - } - -diff --git a/src/main/java/net/minecraft/server/commands/OpCommand.java b/src/main/java/net/minecraft/server/commands/OpCommand.java -index 6854ca4d4fec2b4fa541c3fabf63787665572609..e7b444a10b244828827b3c66c53465206ea8e0ec 100644 ---- a/src/main/java/net/minecraft/server/commands/OpCommand.java -+++ b/src/main/java/net/minecraft/server/commands/OpCommand.java -@@ -46,7 +46,7 @@ public class OpCommand { - if (!playerList.isOp(gameProfile)) { - playerList.op(gameProfile); - i++; -- source.sendSuccess(() -> Component.translatable("commands.op.success", targets.iterator().next().getName()), true); -+ source.sendSuccess(() -> Component.translatable("commands.op.success", gameProfile.getName()), true); // Paper - fixes MC-253721 - } - } - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 75854574aa8d4aef35d84ba4c0fc7df9a67ae48c..3f3124bbb5077a18c3d3afac7748a47e84b8fe35 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1080,7 +1080,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - } - -- boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) { -+ public boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) { // Paper - public - // Spigot start - return this.anyPlayerCloseEnoughForSpawning(pos, false); - } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index f9f00a3862ab829e7695b1da484cb752bdef5c4f..fbee72c0b6e7d73cb0a999330ac7871bb8a7d7e4 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -764,7 +764,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } else { - AABB axisalignedbb = AABB.encapsulatingFullBlocks(blockposition1, blockposition1.atY(this.getMaxY() + 1)).inflate(3.0D); - List list = this.getEntitiesOfClass(LivingEntity.class, axisalignedbb, (entityliving) -> { -- return entityliving != null && entityliving.isAlive() && this.canSeeSky(entityliving.blockPosition()); -+ return entityliving != null && entityliving.isAlive() && this.canSeeSky(entityliving.blockPosition()) && !entityliving.isSpectator(); // Paper - Fix lightning being able to hit spectators (MC-262422) - }); - - if (!list.isEmpty()) { -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 064a7a3e1c4d192010e072a5e985a54135748d87..a706f0855fdf88cc9aece3ba00ef574b9cd8bd11 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -91,7 +91,7 @@ public class ServerPlayerGameMode { - return event; // Paper - Expand PlayerGameModeChangeEvent - } - // CraftBukkit end -- this.setGameModeForPlayer(gameMode, this.previousGameModeForPlayer); -+ this.setGameModeForPlayer(gameMode, this.gameModeForPlayer); // Paper - Fix MC-259571 - this.player.onUpdateAbilities(); - this.player.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit - this.level.updateSleepingPlayerList(); -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 32ed76fca856b7d121e2215748be4f6d1b18791a..72ac67c6d42a1763fd63bd0d0db18ba709f48314 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1831,7 +1831,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.player.swing(enumhand, true); - } - } -- } -+ } else { this.player.containerMenu.sendAllDataToRemote(); } // Paper - Fix inventory desync; MC-99075 - } else { - MutableComponent ichatmutablecomponent1 = Component.translatable("build.tooHigh", i).withStyle(ChatFormatting.RED); - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 0646e435e869b5cc067968feb09ff5c6a979a8a7..61c37bf5f75207085f22093e48986dab8231e1c1 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -261,7 +261,7 @@ public abstract class PlayerList { - } - if (optional.isEmpty() || invalidPlayerWorld[0]) { - // Paper end - reset to main world spawn if first spawn or invalid world -- player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); -+ player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), worldserver1.getSharedSpawnAngle(), 0.0F); // Paper - MC-200092 - fix first spawn pos yaw being ignored - } - // Paper end - Entity#getEntitySpawnReason - player.setServerLevel(worldserver1); -@@ -661,8 +661,10 @@ public abstract class PlayerList { - Player player = entity.getBukkitEntity(); - PlayerLoginEvent event = new PlayerLoginEvent(player, loginlistener.connection.hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.connection.channel.remoteAddress()).getAddress()); - -- if (this.bans.isBanned(gameprofile)) { -- UserBanListEntry gameprofilebanentry = (UserBanListEntry) this.bans.get(gameprofile); -+ // Paper start - Fix MC-158900 -+ UserBanListEntry gameprofilebanentry; -+ if (this.bans.isBanned(gameprofile) && (gameprofilebanentry = this.bans.get(gameprofile)) != null) { -+ // Paper end - Fix MC-158900 - - ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason()); - if (gameprofilebanentry.getExpires() != null) { -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -index 6827426e6e9706909265f84bf97b5fa7105a7fea..7324da6b7dd2623ce394e3827ff77ef684a3b98b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -@@ -78,9 +78,10 @@ public class BreakDoorGoal extends DoorInteractGoal { - return; - } - // CraftBukkit end -+ final net.minecraft.world.level.block.state.BlockState oldState = this.mob.level().getBlockState(this.doorPos); // Paper - fix MC-263999 - this.mob.level().removeBlock(this.doorPos, false); - this.mob.level().levelEvent(1021, this.doorPos, 0); -- this.mob.level().levelEvent(2001, this.doorPos, Block.getId(this.mob.level().getBlockState(this.doorPos))); -+ this.mob.level().levelEvent(2001, this.doorPos, Block.getId(oldState)); // Paper - fix MC-263999 - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -index 9e6f946e6d2878aa3fa8abe0f6fa4770d18676d3..32bb591371fe78ba10a2bc52389ef33978cbc0eb 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -@@ -31,6 +31,11 @@ public class EatBlockGoal extends Goal { - - @Override - public boolean canUse() { -+ // Paper start - Fix MC-210802 -+ if (!((net.minecraft.server.level.ServerLevel) this.level).chunkSource.chunkMap.anyPlayerCloseEnoughForSpawning(this.mob.chunkPosition())) { -+ return false; -+ } -+ // Paper end - if (this.mob.getRandom().nextInt(this.mob.isBaby() ? 50 : 1000) != 0) { - return false; - } else { -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java -index ef71b3ef4444c05b4211de87e1c8ec52cbe3e72a..137ec75ee803789deb7b1ca93dd9369c9af362b9 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java -@@ -21,6 +21,13 @@ public class SwellGoal extends Goal { - return this.creeper.getSwellDir() > 0 || livingEntity != null && this.creeper.distanceToSqr(livingEntity) < 9.0; - } - -+ // Paper start - Fix MC-179072 -+ @Override -+ public boolean canContinueToUse() { -+ return !net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(this.creeper.getTarget()) && canUse(); -+ } -+ // Paper end -+ - @Override - public void start() { - this.creeper.getNavigation().stop(); -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 14b47d6fa189f2a666b12ef7e7708d204c2b0452..4c6dc427b90012b0945e073dd905dc7e8d1bec82 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -247,9 +247,10 @@ public class Goat extends Animal { - player.setItemInHand(hand, itemstack1); - return InteractionResult.SUCCESS; - } else { -+ boolean isFood = this.isFood(itemstack); // Paper - track before stack is possibly decreased to 0 (Fixes MC-244739) - InteractionResult enuminteractionresult = super.mobInteract(player, hand); - -- if (enuminteractionresult.consumesAction() && this.isFood(itemstack)) { -+ if (enuminteractionresult.consumesAction() && isFood) { // Paper - this.playEatingSound(); - } - -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -index 30af4cbb17148c247a46c0346419d6c838dbc9d2..65f7f1f98f415a564aadb440d3a67143699e43db 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -@@ -272,6 +272,14 @@ public class ItemFrame extends HangingEntity { - return (ItemStack) this.getEntityData().get(ItemFrame.DATA_ITEM); - } - -+ // Paper start - Fix MC-123848 (spawn item frame drops above block) -+ @Nullable -+ @Override -+ public net.minecraft.world.entity.item.ItemEntity spawnAtLocation(ServerLevel serverLevel, ItemStack stack) { -+ return this.spawnAtLocation(serverLevel, stack, getDirection().equals(Direction.DOWN) ? -0.6F : 0.0F); -+ } -+ // Paper end -+ - @Nullable - public MapId getFramedMapId(ItemStack stack) { - return (MapId) stack.get(DataComponents.MAP_ID); -diff --git a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -index 15a1ea01917ce57c2457094186dde937c21ffb22..b0236c7bf9441aa84d3795ffed05dd6099f29636 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -+++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -@@ -82,8 +82,8 @@ public class CatSpawner implements CustomSpawner { - if (cat == null) { - return 0; - } else { -+ cat.moveTo(pos, 0.0F, 0.0F); // Paper - move up - Fix MC-147659 - cat.finalizeSpawn(world, world.getCurrentDifficultyAt(pos), EntitySpawnReason.NATURAL, null); -- cat.moveTo(pos, 0.0F, 0.0F); - world.addFreshEntityWithPassengers(cat); - return 1; - } -diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -index cad0b581c992edc5cd312a727695a443e26e96d8..9db647cfbd3f9c884465cf3d3a1b911d46a3da58 100644 ---- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -@@ -164,6 +164,11 @@ public class BeaconMenu extends AbstractContainerMenu { - // Paper end - Add PlayerChangeBeaconEffectEvent - - public void updateEffects(Optional> primary, Optional> secondary) { -+ // Paper start - fix MC-174630 - validate secondary power -+ if (secondary.isPresent() && secondary.get() != net.minecraft.world.effect.MobEffects.REGENERATION && (primary.isPresent() && secondary.get() != primary.get())) { -+ secondary = Optional.empty(); -+ } -+ // Paper end - if (this.paymentSlot.hasItem()) { - // Paper start - Add PlayerChangeBeaconEffectEvent - io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent event = new io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent((org.bukkit.entity.Player) this.player.player.getBukkitEntity(), convert(primary), convert(secondary), this.access.getLocation().getBlock()); -diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -index 7dd6b7c0ea472cfbc7ece55bc64bc5d85be4a6c0..6dcb571e9f35fbae724be69dc113b0c33eca63b3 100644 ---- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -@@ -72,7 +72,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { - if (entity.isOnFire() && this.isEntityInsideContent(state, pos, entity)) { - // CraftBukkit start - moved down - // entity.clearFire(); -- if (entity.mayInteract(worldserver, pos)) { -+ if ((entity instanceof net.minecraft.world.entity.player.Player || worldserver.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING)) && entity.mayInteract(worldserver, pos)) { // Paper - Fixes MC-248588 - if (this.handleEntityOnFireInsideWithEvent(state, world, pos, entity)) { // Paper - fix powdered snow cauldron extinguishing entities - entity.clearFire(); - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index 9c1267df7057caa3500c7a9e6c705ea58c2b5e11..4d36aa195332c2ff6fa7bc5fff61ff7dc80a3fd5 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -531,13 +531,10 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - - @Override - public void fillStackedContents(StackedItemContents finder) { -- Iterator iterator = this.items.iterator(); -- -- while (iterator.hasNext()) { -- ItemStack itemstack = (ItemStack) iterator.next(); -- -- finder.accountStack(itemstack); -- } -+ // Paper start - don't account fuel stack (fixes MC-243057) -+ finder.accountStack(this.items.get(SLOT_INPUT)); -+ finder.accountStack(this.items.get(SLOT_RESULT)); -+ // Paper end - - } - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index 8aab6f68f576fb022eb59798585e264f5aafbc69..edd6017937a7f20a1b43fa15204ec130b524b52b 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -295,7 +295,11 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, worldPosition); - new io.papermc.paper.event.block.BeaconDeactivatedEvent(block).callEvent(); - // Paper end - beacon activation/deactivation events -+ // Paper start - fix MC-153086 -+ if (this.levels > 0 && !this.beamSections.isEmpty()) { - BeaconBlockEntity.playSound(this.level, this.worldPosition, SoundEvents.BEACON_DEACTIVATE); -+ } -+ // Paper end - super.setRemoved(); - } - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java -index e64a30577e9000e5c4d22fd3d9cf8a9381c5c459..b9690f31d410e82d833b2ca805df2fa68abcb6d1 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java -@@ -101,17 +101,19 @@ public class TrialSpawnerData { - this.ejectingLootTable = rewardLootTable; - } - -- public void reset() { -+ public void reset(TrialSpawner logic) { // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 - this.currentMobs.clear(); - this.nextSpawnData = Optional.empty(); -- this.resetStatistics(); -+ this.resetStatistics(logic); - } - -- public void resetStatistics() { -+ public void resetStatistics(TrialSpawner logic) { // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 - this.detectedPlayers.clear(); - this.totalMobsSpawned = 0; - this.nextMobSpawnsAt = 0L; - this.cooldownEndsAt = 0L; -+ this.nextSpawnData = Optional.empty(); -+ if (!logic.getConfig().spawnPotentialsDefinition().isEmpty()) this.nextSpawnData = Optional.empty(); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 - } - - public boolean hasMobToSpawn(TrialSpawner logic, RandomSource random) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java -index 83cdeee5e2ce115ff696a5afc5465dc4301779b9..027d5c4117feba1e152d0ecf9923aef77ba72207 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerState.java -@@ -68,7 +68,7 @@ public enum TrialSpawnerState implements StringRepresentable { - case INACTIVE -> trialSpawnerData.getOrCreateDisplayEntity(logic, world, WAITING_FOR_PLAYERS) == null ? this : WAITING_FOR_PLAYERS; - case WAITING_FOR_PLAYERS -> { - if (!logic.canSpawnInLevel(world)) { -- trialSpawnerData.resetStatistics(); -+ trialSpawnerData.resetStatistics(logic); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 - yield this; - } else if (!trialSpawnerData.hasMobToSpawn(logic, world.random)) { - yield INACTIVE; -@@ -79,7 +79,7 @@ public enum TrialSpawnerState implements StringRepresentable { - } - case ACTIVE -> { - if (!logic.canSpawnInLevel(world)) { -- trialSpawnerData.resetStatistics(); -+ trialSpawnerData.resetStatistics(logic); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 - yield WAITING_FOR_PLAYERS; - } else if (!trialSpawnerData.hasMobToSpawn(logic, world.random)) { - yield INACTIVE; -@@ -145,7 +145,7 @@ public enum TrialSpawnerState implements StringRepresentable { - yield ACTIVE; - } else if (trialSpawnerData.isCooldownFinished(world)) { - logic.removeOminous(world, pos); -- trialSpawnerData.reset(); -+ trialSpawnerData.reset(logic); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 - yield WAITING_FOR_PLAYERS; - } else { - yield this; diff --git a/patches/server/0740-Remove-unnecessary-onTrackingStart-during-navigation.patch b/patches/server/0740-Remove-unnecessary-onTrackingStart-during-navigation.patch new file mode 100644 index 0000000000..ad0baf535f --- /dev/null +++ b/patches/server/0740-Remove-unnecessary-onTrackingStart-during-navigation.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Mon, 3 Oct 2022 20:48:19 +0200 +Subject: [PATCH] Remove unnecessary onTrackingStart during navigation warning + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index d01f42aad003c7b0ea5700d32109eed4a264fa4c..45e61a08152517a61260e662764d8bb0335537e3 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2237,7 +2237,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + + if (entity instanceof Mob entityinsentient) { +- if (ServerLevel.this.isUpdatingNavigations) { ++ if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning + String s = "onTrackingStart called during navigation iteration"; + + Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); +@@ -2317,7 +2317,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + + if (entity instanceof Mob entityinsentient) { +- if (ServerLevel.this.isUpdatingNavigations) { ++ if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning + String s = "onTrackingStart called during navigation iteration"; + + Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); diff --git a/patches/server/0741-Fix-custom-piglin-loved-items.patch b/patches/server/0741-Fix-custom-piglin-loved-items.patch new file mode 100644 index 0000000000..358bd47f1e --- /dev/null +++ b/patches/server/0741-Fix-custom-piglin-loved-items.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 4 Jul 2022 21:50:44 -0700 +Subject: [PATCH] Fix custom piglin loved items + +Upstream didn't modify the isLovedItem check in wantsToPickup +so piglins never actually tried to pickup interestItems + +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java +index 4f3048615a34fc2c067e09aec76af94cde6a74e0..5c26beef2d3f3d4afa51950ddeb7089989218462 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java +@@ -405,7 +405,7 @@ public class PiglinAi { + } else { + boolean flag = piglin.canAddToInventory(stack); + +- return stack.is(Items.GOLD_NUGGET) ? flag : (PiglinAi.isFood(stack) ? !PiglinAi.hasEatenRecently(piglin) && flag : (!PiglinAi.isLovedItem(stack) ? piglin.canReplaceCurrentItem(stack) : PiglinAi.isNotHoldingLovedItemInOffHand(piglin) && flag)); ++ return stack.is(Items.GOLD_NUGGET) ? flag : (PiglinAi.isFood(stack) ? !PiglinAi.hasEatenRecently(piglin) && flag : (!PiglinAi.isLovedItem(stack, piglin) ? piglin.canReplaceCurrentItem(stack) : PiglinAi.isNotHoldingLovedItemInOffHand(piglin) && flag)); // Paper - upstream missed isLovedItem check + } + } + diff --git a/patches/server/0741-Remove-unnecessary-onTrackingStart-during-navigation.patch b/patches/server/0741-Remove-unnecessary-onTrackingStart-during-navigation.patch deleted file mode 100644 index b26563ecdf..0000000000 --- a/patches/server/0741-Remove-unnecessary-onTrackingStart-during-navigation.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Mon, 3 Oct 2022 20:48:19 +0200 -Subject: [PATCH] Remove unnecessary onTrackingStart during navigation warning - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index fbee72c0b6e7d73cb0a999330ac7871bb8a7d7e4..18d39f4a8b1b15960a9b8351d46a62bea848f9c8 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2267,7 +2267,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - if (entity instanceof Mob entityinsentient) { -- if (ServerLevel.this.isUpdatingNavigations) { -+ if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning - String s = "onTrackingStart called during navigation iteration"; - - Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); -@@ -2347,7 +2347,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - if (entity instanceof Mob entityinsentient) { -- if (ServerLevel.this.isUpdatingNavigations) { -+ if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning - String s = "onTrackingStart called during navigation iteration"; - - Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); diff --git a/patches/server/0742-EntityPickupItemEvent-fixes.patch b/patches/server/0742-EntityPickupItemEvent-fixes.patch new file mode 100644 index 0000000000..839a01673d --- /dev/null +++ b/patches/server/0742-EntityPickupItemEvent-fixes.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 4 Jul 2022 21:45:36 -0700 +Subject: [PATCH] EntityPickupItemEvent fixes + +Fixes double firing of the event in PiglinAi + +Fixes cancelling the event for piglins still triggering the +advancement trigger + +Fires the event when a Raider tries to pick up a raid banner +to become raid leader. + +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java +index 15a49e3541c8b45db5e472a64fa0cb94c5a72f67..e04d2c5e75dc774fe893a552474fdb8045c32693 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -429,7 +429,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + + @Override + protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) { +- this.onItemPickup(itemEntity); ++ // this.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; call in PiglinAi#pickUpItem after EntityPickupItemEvent is fired + PiglinAi.pickUpItem(world, this, itemEntity); + } + +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java +index 5c26beef2d3f3d4afa51950ddeb7089989218462..e283b1296c1e831376bfe9491cbf02ed4b3fffe4 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java +@@ -244,11 +244,16 @@ public class PiglinAi { + ItemStack itemstack; + + // CraftBukkit start +- if (itemEntity.getItem().is(Items.GOLD_NUGGET) && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()) { ++ // Paper start - EntityPickupItemEvent fixes; fix event firing twice ++ if (itemEntity.getItem().is(Items.GOLD_NUGGET)/* && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()*/) { // Paper ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()) return; ++ piglin.onItemPickup(itemEntity); // Paper - moved from Piglin#pickUpItem - call prior to item entity modification ++ // Paper end + piglin.take(itemEntity, itemEntity.getItem().getCount()); + itemstack = itemEntity.getItem(); + itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause + } else if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, itemEntity.getItem().getCount() - 1, false).isCancelled()) { ++ piglin.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; moved from Piglin#pickUpItem - call prior to item entity modification + piglin.take(itemEntity, 1); + itemstack = PiglinAi.removeOneItemFromItemEntity(itemEntity); + } else { +@@ -263,7 +268,7 @@ public class PiglinAi { + } else if (PiglinAi.isFood(itemstack) && !PiglinAi.hasEatenRecently(piglin)) { + PiglinAi.eat(piglin); + } else { +- boolean flag = !piglin.equipItemIfPossible(world, itemstack, itemEntity).equals(ItemStack.EMPTY); // CraftBukkit ++ boolean flag = !piglin.equipItemIfPossible(world, itemstack, null).equals(ItemStack.EMPTY); // CraftBukkit // Paper - pass null item entity to prevent duplicate pickup item event call - called above. + + if (!flag) { + PiglinAi.putInInventory(piglin, itemstack); +diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java +index 45375ccdcf730732dd915304dea2f523807eedd6..ab132041982df2a701e4baea8195873f31b4a5fb 100644 +--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java ++++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java +@@ -228,6 +228,11 @@ public abstract class Raider extends PatrollingMonster { + boolean flag = this.hasActiveRaid() && this.getCurrentRaid().getLeader(this.getWave()) != null; + + if (this.hasActiveRaid() && !flag && ItemStack.matches(itemstack, Raid.getOminousBannerInstance(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) { ++ // Paper start - EntityPickupItemEvent fixes ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, itemEntity, 0, false).isCancelled()) { ++ return; ++ } ++ // Paper end - EntityPickupItemEvent fixes + EquipmentSlot enumitemslot = EquipmentSlot.HEAD; + ItemStack itemstack1 = this.getItemBySlot(enumitemslot); + double d0 = (double) this.getEquipmentDropChance(enumitemslot); diff --git a/patches/server/0742-Fix-custom-piglin-loved-items.patch b/patches/server/0742-Fix-custom-piglin-loved-items.patch deleted file mode 100644 index 358bd47f1e..0000000000 --- a/patches/server/0742-Fix-custom-piglin-loved-items.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 4 Jul 2022 21:50:44 -0700 -Subject: [PATCH] Fix custom piglin loved items - -Upstream didn't modify the isLovedItem check in wantsToPickup -so piglins never actually tried to pickup interestItems - -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -index 4f3048615a34fc2c067e09aec76af94cde6a74e0..5c26beef2d3f3d4afa51950ddeb7089989218462 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -@@ -405,7 +405,7 @@ public class PiglinAi { - } else { - boolean flag = piglin.canAddToInventory(stack); - -- return stack.is(Items.GOLD_NUGGET) ? flag : (PiglinAi.isFood(stack) ? !PiglinAi.hasEatenRecently(piglin) && flag : (!PiglinAi.isLovedItem(stack) ? piglin.canReplaceCurrentItem(stack) : PiglinAi.isNotHoldingLovedItemInOffHand(piglin) && flag)); -+ return stack.is(Items.GOLD_NUGGET) ? flag : (PiglinAi.isFood(stack) ? !PiglinAi.hasEatenRecently(piglin) && flag : (!PiglinAi.isLovedItem(stack, piglin) ? piglin.canReplaceCurrentItem(stack) : PiglinAi.isNotHoldingLovedItemInOffHand(piglin) && flag)); // Paper - upstream missed isLovedItem check - } - } - diff --git a/patches/server/0743-Correctly-handle-interactions-with-items-on-cooldown.patch b/patches/server/0743-Correctly-handle-interactions-with-items-on-cooldown.patch new file mode 100644 index 0000000000..a86affadb8 --- /dev/null +++ b/patches/server/0743-Correctly-handle-interactions-with-items-on-cooldown.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 16 Jun 2022 21:57:02 -0700 +Subject: [PATCH] Correctly handle interactions with items on cooldown + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index a706f0855fdf88cc9aece3ba00ef574b9cd8bd11..2aee9c2fbe38076317a3de7c3fdbd6988b64b389 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -520,6 +520,7 @@ public class ServerPlayerGameMode { + BlockPos blockposition = hitResult.getBlockPos(); + BlockState iblockdata = world.getBlockState(blockposition); + boolean cancelledBlock = false; ++ boolean cancelledItem = false; // Paper - correctly handle items on cooldown + + if (!iblockdata.getBlock().isEnabled(world.enabledFeatures())) { + return InteractionResult.FAIL; +@@ -529,10 +530,10 @@ public class ServerPlayerGameMode { + } + + if (player.getCooldowns().isOnCooldown(stack)) { +- cancelledBlock = true; ++ cancelledItem = true; // Paper - correctly handle items on cooldown + } + +- PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, blockposition, hitResult.getDirection(), stack, cancelledBlock, hand, hitResult.getLocation()); ++ PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, blockposition, hitResult.getDirection(), stack, cancelledBlock, cancelledItem, hand, hitResult.getLocation()); // Paper - correctly handle items on cooldown + this.firedInteract = true; + this.interactResult = event.useItemInHand() == Event.Result.DENY; + this.interactPosition = blockposition.immutable(); +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index f54a4c263eeb4df40c72c20c3c480ce74718a718..ea0241de1a7ef64059cddcb43c41f56b91901897 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -555,6 +555,12 @@ public class CraftEventFactory { + } + + public static PlayerInteractEvent callPlayerInteractEvent(net.minecraft.world.entity.player.Player who, Action action, BlockPos position, Direction direction, ItemStack itemstack, boolean cancelledBlock, InteractionHand hand, Vec3 targetPos) { ++ // Paper start - cancelledItem param ++ return CraftEventFactory.callPlayerInteractEvent(who, action, position, direction, itemstack, cancelledBlock, false, hand, targetPos); ++ } ++ ++ public static PlayerInteractEvent callPlayerInteractEvent(net.minecraft.world.entity.player.Player who, Action action, BlockPos position, Direction direction, ItemStack itemstack, boolean cancelledBlock, boolean cancelledItem, InteractionHand hand, Vec3 targetPos) { ++ // Paper end - cancelledItem param + Player player = (who == null) ? null : (Player) who.getBukkitEntity(); + CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack); + +@@ -589,6 +595,11 @@ public class CraftEventFactory { + if (cancelledBlock) { + event.setUseInteractedBlock(Event.Result.DENY); + } ++ // Paper start ++ if (cancelledItem) { ++ event.setUseItemInHand(Result.DENY); ++ } ++ // Paper end + craftServer.getPluginManager().callEvent(event); + + return event; diff --git a/patches/server/0743-EntityPickupItemEvent-fixes.patch b/patches/server/0743-EntityPickupItemEvent-fixes.patch deleted file mode 100644 index 839a01673d..0000000000 --- a/patches/server/0743-EntityPickupItemEvent-fixes.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 4 Jul 2022 21:45:36 -0700 -Subject: [PATCH] EntityPickupItemEvent fixes - -Fixes double firing of the event in PiglinAi - -Fixes cancelling the event for piglins still triggering the -advancement trigger - -Fires the event when a Raider tries to pick up a raid banner -to become raid leader. - -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index 15a49e3541c8b45db5e472a64fa0cb94c5a72f67..e04d2c5e75dc774fe893a552474fdb8045c32693 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -429,7 +429,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - - @Override - protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) { -- this.onItemPickup(itemEntity); -+ // this.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; call in PiglinAi#pickUpItem after EntityPickupItemEvent is fired - PiglinAi.pickUpItem(world, this, itemEntity); - } - -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -index 5c26beef2d3f3d4afa51950ddeb7089989218462..e283b1296c1e831376bfe9491cbf02ed4b3fffe4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -@@ -244,11 +244,16 @@ public class PiglinAi { - ItemStack itemstack; - - // CraftBukkit start -- if (itemEntity.getItem().is(Items.GOLD_NUGGET) && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()) { -+ // Paper start - EntityPickupItemEvent fixes; fix event firing twice -+ if (itemEntity.getItem().is(Items.GOLD_NUGGET)/* && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()*/) { // Paper -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()) return; -+ piglin.onItemPickup(itemEntity); // Paper - moved from Piglin#pickUpItem - call prior to item entity modification -+ // Paper end - piglin.take(itemEntity, itemEntity.getItem().getCount()); - itemstack = itemEntity.getItem(); - itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause - } else if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, itemEntity.getItem().getCount() - 1, false).isCancelled()) { -+ piglin.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; moved from Piglin#pickUpItem - call prior to item entity modification - piglin.take(itemEntity, 1); - itemstack = PiglinAi.removeOneItemFromItemEntity(itemEntity); - } else { -@@ -263,7 +268,7 @@ public class PiglinAi { - } else if (PiglinAi.isFood(itemstack) && !PiglinAi.hasEatenRecently(piglin)) { - PiglinAi.eat(piglin); - } else { -- boolean flag = !piglin.equipItemIfPossible(world, itemstack, itemEntity).equals(ItemStack.EMPTY); // CraftBukkit -+ boolean flag = !piglin.equipItemIfPossible(world, itemstack, null).equals(ItemStack.EMPTY); // CraftBukkit // Paper - pass null item entity to prevent duplicate pickup item event call - called above. - - if (!flag) { - PiglinAi.putInInventory(piglin, itemstack); -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java -index 45375ccdcf730732dd915304dea2f523807eedd6..ab132041982df2a701e4baea8195873f31b4a5fb 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raider.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java -@@ -228,6 +228,11 @@ public abstract class Raider extends PatrollingMonster { - boolean flag = this.hasActiveRaid() && this.getCurrentRaid().getLeader(this.getWave()) != null; - - if (this.hasActiveRaid() && !flag && ItemStack.matches(itemstack, Raid.getOminousBannerInstance(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) { -+ // Paper start - EntityPickupItemEvent fixes -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, itemEntity, 0, false).isCancelled()) { -+ return; -+ } -+ // Paper end - EntityPickupItemEvent fixes - EquipmentSlot enumitemslot = EquipmentSlot.HEAD; - ItemStack itemstack1 = this.getItemBySlot(enumitemslot); - double d0 = (double) this.getEquipmentDropChance(enumitemslot); diff --git a/patches/server/0744-Add-PlayerInventorySlotChangeEvent.patch b/patches/server/0744-Add-PlayerInventorySlotChangeEvent.patch new file mode 100644 index 0000000000..cca34b90d0 --- /dev/null +++ b/patches/server/0744-Add-PlayerInventorySlotChangeEvent.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakub Zacek +Date: Sun, 24 Apr 2022 22:56:59 +0200 +Subject: [PATCH] Add PlayerInventorySlotChangeEvent + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 312225a15261f2e80fbf6133c75c567574ade181..04e3c75c9abfaccb6d2d59d234e5169258b77553 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -381,6 +381,25 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + } + } ++ // Paper start - Add PlayerInventorySlotChangeEvent ++ @Override ++ public void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack oldStack, ItemStack stack) { ++ Slot slot = handler.getSlot(slotId); ++ if (!(slot instanceof ResultSlot)) { ++ if (slot.container == ServerPlayer.this.getInventory()) { ++ if (io.papermc.paper.event.player.PlayerInventorySlotChangeEvent.getHandlerList().getRegisteredListeners().length == 0) { ++ CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack); ++ return; ++ } ++ io.papermc.paper.event.player.PlayerInventorySlotChangeEvent event = new io.papermc.paper.event.player.PlayerInventorySlotChangeEvent(ServerPlayer.this.getBukkitEntity(), slotId, CraftItemStack.asBukkitCopy(oldStack), CraftItemStack.asBukkitCopy(stack)); ++ event.callEvent(); ++ if (event.shouldTriggerAdvancements()) { ++ CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack); ++ } ++ } ++ } ++ } ++ // Paper end - Add PlayerInventorySlotChangeEvent + + @Override + public void dataChanged(AbstractContainerMenu handler, int property, int value) {} +diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +index 3b92fb173f623a05ae99c86d98f2ecdf907f58c4..d830504d08c9de92797c432a868c1ee9dfc46a91 100644 +--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -330,7 +330,7 @@ public abstract class AbstractContainerMenu { + while (iterator.hasNext()) { + ContainerListener icrafting = (ContainerListener) iterator.next(); + +- icrafting.slotChanged(this, slot, itemstack2); ++ icrafting.slotChanged(this, slot, itemstack1, itemstack2); // Paper - Add PlayerInventorySlotChangeEvent + } + } + +diff --git a/src/main/java/net/minecraft/world/inventory/ContainerListener.java b/src/main/java/net/minecraft/world/inventory/ContainerListener.java +index 0e19cc55646625bf32a354d3df2dc2d6bcff96f4..eba024c9aadef8902aacccea1584ffbee6c04e44 100644 +--- a/src/main/java/net/minecraft/world/inventory/ContainerListener.java ++++ b/src/main/java/net/minecraft/world/inventory/ContainerListener.java +@@ -5,5 +5,11 @@ import net.minecraft.world.item.ItemStack; + public interface ContainerListener { + void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack stack); + ++ // Paper start - Add PlayerInventorySlotChangeEvent ++ default void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack oldStack, ItemStack stack) { ++ slotChanged(handler, slotId, stack); ++ } ++ // Paper end - Add PlayerInventorySlotChangeEvent ++ + void dataChanged(AbstractContainerMenu handler, int property, int value); + } diff --git a/patches/server/0744-Correctly-handle-interactions-with-items-on-cooldown.patch b/patches/server/0744-Correctly-handle-interactions-with-items-on-cooldown.patch deleted file mode 100644 index a86affadb8..0000000000 --- a/patches/server/0744-Correctly-handle-interactions-with-items-on-cooldown.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 16 Jun 2022 21:57:02 -0700 -Subject: [PATCH] Correctly handle interactions with items on cooldown - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index a706f0855fdf88cc9aece3ba00ef574b9cd8bd11..2aee9c2fbe38076317a3de7c3fdbd6988b64b389 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -520,6 +520,7 @@ public class ServerPlayerGameMode { - BlockPos blockposition = hitResult.getBlockPos(); - BlockState iblockdata = world.getBlockState(blockposition); - boolean cancelledBlock = false; -+ boolean cancelledItem = false; // Paper - correctly handle items on cooldown - - if (!iblockdata.getBlock().isEnabled(world.enabledFeatures())) { - return InteractionResult.FAIL; -@@ -529,10 +530,10 @@ public class ServerPlayerGameMode { - } - - if (player.getCooldowns().isOnCooldown(stack)) { -- cancelledBlock = true; -+ cancelledItem = true; // Paper - correctly handle items on cooldown - } - -- PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, blockposition, hitResult.getDirection(), stack, cancelledBlock, hand, hitResult.getLocation()); -+ PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, blockposition, hitResult.getDirection(), stack, cancelledBlock, cancelledItem, hand, hitResult.getLocation()); // Paper - correctly handle items on cooldown - this.firedInteract = true; - this.interactResult = event.useItemInHand() == Event.Result.DENY; - this.interactPosition = blockposition.immutable(); -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index f54a4c263eeb4df40c72c20c3c480ce74718a718..ea0241de1a7ef64059cddcb43c41f56b91901897 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -555,6 +555,12 @@ public class CraftEventFactory { - } - - public static PlayerInteractEvent callPlayerInteractEvent(net.minecraft.world.entity.player.Player who, Action action, BlockPos position, Direction direction, ItemStack itemstack, boolean cancelledBlock, InteractionHand hand, Vec3 targetPos) { -+ // Paper start - cancelledItem param -+ return CraftEventFactory.callPlayerInteractEvent(who, action, position, direction, itemstack, cancelledBlock, false, hand, targetPos); -+ } -+ -+ public static PlayerInteractEvent callPlayerInteractEvent(net.minecraft.world.entity.player.Player who, Action action, BlockPos position, Direction direction, ItemStack itemstack, boolean cancelledBlock, boolean cancelledItem, InteractionHand hand, Vec3 targetPos) { -+ // Paper end - cancelledItem param - Player player = (who == null) ? null : (Player) who.getBukkitEntity(); - CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack); - -@@ -589,6 +595,11 @@ public class CraftEventFactory { - if (cancelledBlock) { - event.setUseInteractedBlock(Event.Result.DENY); - } -+ // Paper start -+ if (cancelledItem) { -+ event.setUseItemInHand(Result.DENY); -+ } -+ // Paper end - craftServer.getPluginManager().callEvent(event); - - return event; diff --git a/patches/server/0745-Add-PlayerInventorySlotChangeEvent.patch b/patches/server/0745-Add-PlayerInventorySlotChangeEvent.patch deleted file mode 100644 index cca34b90d0..0000000000 --- a/patches/server/0745-Add-PlayerInventorySlotChangeEvent.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jakub Zacek -Date: Sun, 24 Apr 2022 22:56:59 +0200 -Subject: [PATCH] Add PlayerInventorySlotChangeEvent - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 312225a15261f2e80fbf6133c75c567574ade181..04e3c75c9abfaccb6d2d59d234e5169258b77553 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -381,6 +381,25 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - } - } -+ // Paper start - Add PlayerInventorySlotChangeEvent -+ @Override -+ public void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack oldStack, ItemStack stack) { -+ Slot slot = handler.getSlot(slotId); -+ if (!(slot instanceof ResultSlot)) { -+ if (slot.container == ServerPlayer.this.getInventory()) { -+ if (io.papermc.paper.event.player.PlayerInventorySlotChangeEvent.getHandlerList().getRegisteredListeners().length == 0) { -+ CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack); -+ return; -+ } -+ io.papermc.paper.event.player.PlayerInventorySlotChangeEvent event = new io.papermc.paper.event.player.PlayerInventorySlotChangeEvent(ServerPlayer.this.getBukkitEntity(), slotId, CraftItemStack.asBukkitCopy(oldStack), CraftItemStack.asBukkitCopy(stack)); -+ event.callEvent(); -+ if (event.shouldTriggerAdvancements()) { -+ CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack); -+ } -+ } -+ } -+ } -+ // Paper end - Add PlayerInventorySlotChangeEvent - - @Override - public void dataChanged(AbstractContainerMenu handler, int property, int value) {} -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index 3b92fb173f623a05ae99c86d98f2ecdf907f58c4..d830504d08c9de92797c432a868c1ee9dfc46a91 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -330,7 +330,7 @@ public abstract class AbstractContainerMenu { - while (iterator.hasNext()) { - ContainerListener icrafting = (ContainerListener) iterator.next(); - -- icrafting.slotChanged(this, slot, itemstack2); -+ icrafting.slotChanged(this, slot, itemstack1, itemstack2); // Paper - Add PlayerInventorySlotChangeEvent - } - } - -diff --git a/src/main/java/net/minecraft/world/inventory/ContainerListener.java b/src/main/java/net/minecraft/world/inventory/ContainerListener.java -index 0e19cc55646625bf32a354d3df2dc2d6bcff96f4..eba024c9aadef8902aacccea1584ffbee6c04e44 100644 ---- a/src/main/java/net/minecraft/world/inventory/ContainerListener.java -+++ b/src/main/java/net/minecraft/world/inventory/ContainerListener.java -@@ -5,5 +5,11 @@ import net.minecraft.world.item.ItemStack; - public interface ContainerListener { - void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack stack); - -+ // Paper start - Add PlayerInventorySlotChangeEvent -+ default void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack oldStack, ItemStack stack) { -+ slotChanged(handler, slotId, stack); -+ } -+ // Paper end - Add PlayerInventorySlotChangeEvent -+ - void dataChanged(AbstractContainerMenu handler, int property, int value); - } diff --git a/patches/server/0745-Elder-Guardian-appearance-API.patch b/patches/server/0745-Elder-Guardian-appearance-API.patch new file mode 100644 index 0000000000..772a3c2cd3 --- /dev/null +++ b/patches/server/0745-Elder-Guardian-appearance-API.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Tue, 11 Oct 2022 20:38:47 +0300 +Subject: [PATCH] Elder Guardian appearance API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 58f3ca95b1d79269bed3b6473cd69d8988ede162..667796909ea6b56b93ec591aae1c393ec2f8940a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -3328,6 +3328,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + // Paper end + ++ // Paper start ++ @Override ++ public void showElderGuardian(boolean silent) { ++ if (getHandle().connection != null) getHandle().connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, silent ? 0F : 1F)); ++ } ++ // Paper end ++ + public Player.Spigot spigot() + { + return this.spigot; diff --git a/patches/server/0746-Add-entity-knockback-API.patch b/patches/server/0746-Add-entity-knockback-API.patch new file mode 100644 index 0000000000..71f4427274 --- /dev/null +++ b/patches/server/0746-Add-entity-knockback-API.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MelnCat +Date: Sun, 16 Oct 2022 12:10:17 -0700 +Subject: [PATCH] Add entity knockback API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 14b4c3835388d957653ba34444968bb718ce7f68..4fa19ddb1414282020e118eea298d57d2bf42754 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1146,4 +1146,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + throw new UnsupportedOperationException("Cannot set the hurt direction on a non player"); + } + // Paper end - hurt direction API ++ ++ // Paper start - knockback API ++ @Override ++ public void knockback(final double strength, final double directionX, final double directionZ) { ++ Preconditions.checkArgument(strength > 0, "Knockback strength must be > 0"); ++ this.getHandle().knockback(strength, directionX, directionZ); ++ }; ++ // Paper end - knockback API + } diff --git a/patches/server/0746-Elder-Guardian-appearance-API.patch b/patches/server/0746-Elder-Guardian-appearance-API.patch deleted file mode 100644 index 772a3c2cd3..0000000000 --- a/patches/server/0746-Elder-Guardian-appearance-API.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SoSeDiK -Date: Tue, 11 Oct 2022 20:38:47 +0300 -Subject: [PATCH] Elder Guardian appearance API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 58f3ca95b1d79269bed3b6473cd69d8988ede162..667796909ea6b56b93ec591aae1c393ec2f8940a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3328,6 +3328,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - // Paper end - -+ // Paper start -+ @Override -+ public void showElderGuardian(boolean silent) { -+ if (getHandle().connection != null) getHandle().connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, silent ? 0F : 1F)); -+ } -+ // Paper end -+ - public Player.Spigot spigot() - { - return this.spigot; diff --git a/patches/server/0747-Add-entity-knockback-API.patch b/patches/server/0747-Add-entity-knockback-API.patch deleted file mode 100644 index 71f4427274..0000000000 --- a/patches/server/0747-Add-entity-knockback-API.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Sun, 16 Oct 2022 12:10:17 -0700 -Subject: [PATCH] Add entity knockback API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 14b4c3835388d957653ba34444968bb718ce7f68..4fa19ddb1414282020e118eea298d57d2bf42754 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1146,4 +1146,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - throw new UnsupportedOperationException("Cannot set the hurt direction on a non player"); - } - // Paper end - hurt direction API -+ -+ // Paper start - knockback API -+ @Override -+ public void knockback(final double strength, final double directionX, final double directionZ) { -+ Preconditions.checkArgument(strength > 0, "Knockback strength must be > 0"); -+ this.getHandle().knockback(strength, directionX, directionZ); -+ }; -+ // Paper end - knockback API - } diff --git a/patches/server/0747-Detect-headless-JREs.patch b/patches/server/0747-Detect-headless-JREs.patch new file mode 100644 index 0000000000..e680b6146f --- /dev/null +++ b/patches/server/0747-Detect-headless-JREs.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Sat, 22 Oct 2022 14:47:45 +0200 +Subject: [PATCH] Detect headless JREs + +Crashes caused by the missing AWT dependency come up in the support channels fairly often. +This patch detects the missing dependency and stops the server with a clear error message, +containing a link to instructions on how to install a non-headless JRE. + +diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java +index 68098dfe716e93aafcca4d8d5b5a81d8648b3654..2b7070e0cefa7cf0777df159693750fea14e800b 100644 +--- a/src/main/java/io/papermc/paper/util/ServerEnvironment.java ++++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java +@@ -20,4 +20,14 @@ public class ServerEnvironment { + public static boolean userIsRootOrAdmin() { + return RUNNING_AS_ROOT_OR_ADMIN; + } ++ ++ public static String awtDependencyCheck() { ++ try { ++ new java.awt.Color(0); ++ } catch (UnsatisfiedLinkError e) { ++ return e.getClass().getName() + ": " + e.getMessage(); ++ } ++ ++ return null; ++ } + } +diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java +index cf071610ed662c4a309cc26ee73a74fa490d846f..47cd7c66ac37efebf2f63c49d78dd8fe44a70ef8 100644 +--- a/src/main/java/net/minecraft/server/Main.java ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -167,6 +167,18 @@ public class Main { + return; + } + ++ // Paper start - Detect headless JRE ++ String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); ++ if (awtException != null) { ++ Main.LOGGER.error("You are using a headless JRE distribution."); ++ Main.LOGGER.error("This distribution is missing certain graphic libraries that the Minecraft server needs to function."); ++ Main.LOGGER.error("For instructions on how to install the non-headless JRE, see https://docs.papermc.io/misc/java-install"); ++ Main.LOGGER.error(""); ++ Main.LOGGER.error(awtException); ++ return; ++ } ++ // Paper end - Detect headless JRE ++ + org.spigotmc.SpigotConfig.disabledAdvancements = spigotConfiguration.getStringList("advancements.disabled"); // Paper - fix SPIGOT-5885, must be set early in init + // Paper start - fix SPIGOT-5824 + File file; diff --git a/patches/server/0748-Detect-headless-JREs.patch b/patches/server/0748-Detect-headless-JREs.patch deleted file mode 100644 index e680b6146f..0000000000 --- a/patches/server/0748-Detect-headless-JREs.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Sat, 22 Oct 2022 14:47:45 +0200 -Subject: [PATCH] Detect headless JREs - -Crashes caused by the missing AWT dependency come up in the support channels fairly often. -This patch detects the missing dependency and stops the server with a clear error message, -containing a link to instructions on how to install a non-headless JRE. - -diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java -index 68098dfe716e93aafcca4d8d5b5a81d8648b3654..2b7070e0cefa7cf0777df159693750fea14e800b 100644 ---- a/src/main/java/io/papermc/paper/util/ServerEnvironment.java -+++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java -@@ -20,4 +20,14 @@ public class ServerEnvironment { - public static boolean userIsRootOrAdmin() { - return RUNNING_AS_ROOT_OR_ADMIN; - } -+ -+ public static String awtDependencyCheck() { -+ try { -+ new java.awt.Color(0); -+ } catch (UnsatisfiedLinkError e) { -+ return e.getClass().getName() + ": " + e.getMessage(); -+ } -+ -+ return null; -+ } - } -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index cf071610ed662c4a309cc26ee73a74fa490d846f..47cd7c66ac37efebf2f63c49d78dd8fe44a70ef8 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -167,6 +167,18 @@ public class Main { - return; - } - -+ // Paper start - Detect headless JRE -+ String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); -+ if (awtException != null) { -+ Main.LOGGER.error("You are using a headless JRE distribution."); -+ Main.LOGGER.error("This distribution is missing certain graphic libraries that the Minecraft server needs to function."); -+ Main.LOGGER.error("For instructions on how to install the non-headless JRE, see https://docs.papermc.io/misc/java-install"); -+ Main.LOGGER.error(""); -+ Main.LOGGER.error(awtException); -+ return; -+ } -+ // Paper end - Detect headless JRE -+ - org.spigotmc.SpigotConfig.disabledAdvancements = spigotConfiguration.getStringList("advancements.disabled"); // Paper - fix SPIGOT-5885, must be set early in init - // Paper start - fix SPIGOT-5824 - File file; diff --git a/patches/server/0748-fix-entity-vehicle-collision-event-not-called.patch b/patches/server/0748-fix-entity-vehicle-collision-event-not-called.patch new file mode 100644 index 0000000000..9b38b32086 --- /dev/null +++ b/patches/server/0748-fix-entity-vehicle-collision-event-not-called.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: lukas81298 +Date: Tue, 12 Jan 2021 14:41:38 +0100 +Subject: [PATCH] fix entity vehicle collision event not called + + +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +index ee7350e19a86ffa115e4bce6b186a2422951e89b..d8fcd6d1edec1f31a861fab4b86cbeb15ddc799d 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +@@ -157,7 +157,15 @@ public abstract class AbstractMinecart extends VehicleEntity { + + @Override + public boolean canCollideWith(Entity other) { +- return AbstractBoat.canVehicleCollide(this, other); ++ // Paper start - fix VehicleEntityCollisionEvent not called when colliding with player ++ boolean collides = AbstractBoat.canVehicleCollide(this, other); ++ if (!collides) { ++ return false; ++ } ++ org.bukkit.event.vehicle.VehicleEntityCollisionEvent collisionEvent = new org.bukkit.event.vehicle.VehicleEntityCollisionEvent((org.bukkit.entity.Vehicle) getBukkitEntity(), other.getBukkitEntity()); ++ ++ return collisionEvent.callEvent(); ++ // Paper end - fix VehicleEntityCollisionEvent not called when colliding with player + } + + @Override diff --git a/patches/server/0749-Add-EntityToggleSitEvent.patch b/patches/server/0749-Add-EntityToggleSitEvent.patch new file mode 100644 index 0000000000..7bab6af93d --- /dev/null +++ b/patches/server/0749-Add-EntityToggleSitEvent.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: KyGuy2002 +Date: Fri, 11 Mar 2022 15:33:10 +0000 +Subject: [PATCH] Add EntityToggleSitEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +index 749ae54ee42229cb32ec5280bc59a88f74fde197..f6a253e063f4a2cf78a036e44431806a0ba270d9 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -87,7 +87,7 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + } + + this.orderedToSit = nbt.getBoolean("Sitting"); +- this.setInSittingPose(this.orderedToSit); ++ this.setInSittingPose(this.orderedToSit, false); // Paper - Add EntityToggleSitEvent + } + + @Override +@@ -167,6 +167,12 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + } + + public void setInSittingPose(boolean inSittingPose) { ++ // Paper start - Add EntityToggleSitEvent ++ this.setInSittingPose(inSittingPose, true); ++ } ++ public void setInSittingPose(boolean inSittingPose, boolean callEvent) { ++ if (callEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), inSittingPose).callEvent()) return; ++ // Paper end - Add EntityToggleSitEvent + byte b0 = (Byte) this.entityData.get(TamableAnimal.DATA_FLAGS_ID); + + if (inSittingPose) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java +index 67ea374ae3c66af434b4aadbe702a44d230fbe09..a9a8ebb2cebe668628d5bdb33fa1399e0ab1e08b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java +@@ -419,7 +419,7 @@ public class Fox extends Animal implements VariantHolder { + + this.setSleeping(nbt.getBoolean("Sleeping")); + this.setVariant(Fox.Variant.byName(nbt.getString("Type"))); +- this.setSitting(nbt.getBoolean("Sitting")); ++ this.setSitting(nbt.getBoolean("Sitting"), false); // Paper - Add EntityToggleSitEvent + this.setIsCrouching(nbt.getBoolean("Crouching")); + if (this.level() instanceof ServerLevel) { + this.setTargetGoals(); +@@ -432,6 +432,12 @@ public class Fox extends Animal implements VariantHolder { + } + + public void setSitting(boolean sitting) { ++ // Paper start - Add EntityToggleSitEvent ++ this.setSitting(sitting, true); ++ } ++ public void setSitting(boolean sitting, boolean fireEvent) { ++ if (fireEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; ++ // Paper end - Add EntityToggleSitEvent + this.setFlag(1, sitting); + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java +index 4f04170b3ec4ff59358e10ccfd0799af3ab590c3..b654bec0fbe903fac24f3bb99399455bf367c68a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java +@@ -134,6 +134,7 @@ public class Panda extends Animal { + } + + public void sit(boolean sitting) { ++ if (!new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; // Paper - Add EntityToggleSitEvent + this.setFlag(8, sitting); + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java +index b6baa40dac6d6bf40c4ee7ee75b8a8e6f60733a1..c99d37a40c63726c11980adccc67d09fd5132885 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java ++++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java +@@ -572,7 +572,7 @@ public class Camel extends AbstractHorse { + } + + public void sitDown() { +- if (!this.isCamelSitting()) { ++ if (!this.isCamelSitting() && new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), true).callEvent()) { // Paper - Add EntityToggleSitEvent + this.makeSound(SoundEvents.CAMEL_SIT); + this.setPose(Pose.SITTING); + this.gameEvent(GameEvent.ENTITY_ACTION); +@@ -581,7 +581,7 @@ public class Camel extends AbstractHorse { + } + + public void standUp() { +- if (this.isCamelSitting()) { ++ if (this.isCamelSitting() && new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), false).callEvent()) { // Paper - Add EntityToggleSitEvent + this.makeSound(SoundEvents.CAMEL_STAND); + this.setPose(Pose.STANDING); + this.gameEvent(GameEvent.ENTITY_ACTION); +@@ -590,6 +590,7 @@ public class Camel extends AbstractHorse { + } + + public void standUpInstantly() { ++ if (this.isCamelSitting() && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), false).callEvent()) return; // Paper - Add EntityToggleSitEvent + this.setPose(Pose.STANDING); + this.gameEvent(GameEvent.ENTITY_ACTION); + this.resetLastPoseChangeTickToFullStand(this.level().getGameTime()); diff --git a/patches/server/0749-fix-entity-vehicle-collision-event-not-called.patch b/patches/server/0749-fix-entity-vehicle-collision-event-not-called.patch deleted file mode 100644 index 9b38b32086..0000000000 --- a/patches/server/0749-fix-entity-vehicle-collision-event-not-called.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: lukas81298 -Date: Tue, 12 Jan 2021 14:41:38 +0100 -Subject: [PATCH] fix entity vehicle collision event not called - - -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -index ee7350e19a86ffa115e4bce6b186a2422951e89b..d8fcd6d1edec1f31a861fab4b86cbeb15ddc799d 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -157,7 +157,15 @@ public abstract class AbstractMinecart extends VehicleEntity { - - @Override - public boolean canCollideWith(Entity other) { -- return AbstractBoat.canVehicleCollide(this, other); -+ // Paper start - fix VehicleEntityCollisionEvent not called when colliding with player -+ boolean collides = AbstractBoat.canVehicleCollide(this, other); -+ if (!collides) { -+ return false; -+ } -+ org.bukkit.event.vehicle.VehicleEntityCollisionEvent collisionEvent = new org.bukkit.event.vehicle.VehicleEntityCollisionEvent((org.bukkit.entity.Vehicle) getBukkitEntity(), other.getBukkitEntity()); -+ -+ return collisionEvent.callEvent(); -+ // Paper end - fix VehicleEntityCollisionEvent not called when colliding with player - } - - @Override diff --git a/patches/server/0750-Add-EntityToggleSitEvent.patch b/patches/server/0750-Add-EntityToggleSitEvent.patch deleted file mode 100644 index 7bab6af93d..0000000000 --- a/patches/server/0750-Add-EntityToggleSitEvent.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: KyGuy2002 -Date: Fri, 11 Mar 2022 15:33:10 +0000 -Subject: [PATCH] Add EntityToggleSitEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -index 749ae54ee42229cb32ec5280bc59a88f74fde197..f6a253e063f4a2cf78a036e44431806a0ba270d9 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -87,7 +87,7 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { - } - - this.orderedToSit = nbt.getBoolean("Sitting"); -- this.setInSittingPose(this.orderedToSit); -+ this.setInSittingPose(this.orderedToSit, false); // Paper - Add EntityToggleSitEvent - } - - @Override -@@ -167,6 +167,12 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { - } - - public void setInSittingPose(boolean inSittingPose) { -+ // Paper start - Add EntityToggleSitEvent -+ this.setInSittingPose(inSittingPose, true); -+ } -+ public void setInSittingPose(boolean inSittingPose, boolean callEvent) { -+ if (callEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), inSittingPose).callEvent()) return; -+ // Paper end - Add EntityToggleSitEvent - byte b0 = (Byte) this.entityData.get(TamableAnimal.DATA_FLAGS_ID); - - if (inSittingPose) { -diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index 67ea374ae3c66af434b4aadbe702a44d230fbe09..a9a8ebb2cebe668628d5bdb33fa1399e0ab1e08b 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Fox.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java -@@ -419,7 +419,7 @@ public class Fox extends Animal implements VariantHolder { - - this.setSleeping(nbt.getBoolean("Sleeping")); - this.setVariant(Fox.Variant.byName(nbt.getString("Type"))); -- this.setSitting(nbt.getBoolean("Sitting")); -+ this.setSitting(nbt.getBoolean("Sitting"), false); // Paper - Add EntityToggleSitEvent - this.setIsCrouching(nbt.getBoolean("Crouching")); - if (this.level() instanceof ServerLevel) { - this.setTargetGoals(); -@@ -432,6 +432,12 @@ public class Fox extends Animal implements VariantHolder { - } - - public void setSitting(boolean sitting) { -+ // Paper start - Add EntityToggleSitEvent -+ this.setSitting(sitting, true); -+ } -+ public void setSitting(boolean sitting, boolean fireEvent) { -+ if (fireEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; -+ // Paper end - Add EntityToggleSitEvent - this.setFlag(1, sitting); - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java -index 4f04170b3ec4ff59358e10ccfd0799af3ab590c3..b654bec0fbe903fac24f3bb99399455bf367c68a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Panda.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java -@@ -134,6 +134,7 @@ public class Panda extends Animal { - } - - public void sit(boolean sitting) { -+ if (!new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; // Paper - Add EntityToggleSitEvent - this.setFlag(8, sitting); - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -index b6baa40dac6d6bf40c4ee7ee75b8a8e6f60733a1..c99d37a40c63726c11980adccc67d09fd5132885 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -@@ -572,7 +572,7 @@ public class Camel extends AbstractHorse { - } - - public void sitDown() { -- if (!this.isCamelSitting()) { -+ if (!this.isCamelSitting() && new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), true).callEvent()) { // Paper - Add EntityToggleSitEvent - this.makeSound(SoundEvents.CAMEL_SIT); - this.setPose(Pose.SITTING); - this.gameEvent(GameEvent.ENTITY_ACTION); -@@ -581,7 +581,7 @@ public class Camel extends AbstractHorse { - } - - public void standUp() { -- if (this.isCamelSitting()) { -+ if (this.isCamelSitting() && new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), false).callEvent()) { // Paper - Add EntityToggleSitEvent - this.makeSound(SoundEvents.CAMEL_STAND); - this.setPose(Pose.STANDING); - this.gameEvent(GameEvent.ENTITY_ACTION); -@@ -590,6 +590,7 @@ public class Camel extends AbstractHorse { - } - - public void standUpInstantly() { -+ if (this.isCamelSitting() && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), false).callEvent()) return; // Paper - Add EntityToggleSitEvent - this.setPose(Pose.STANDING); - this.gameEvent(GameEvent.ENTITY_ACTION); - this.resetLastPoseChangeTickToFullStand(this.level().getGameTime()); diff --git a/patches/server/0750-Add-fire-tick-delay-option.patch b/patches/server/0750-Add-fire-tick-delay-option.patch new file mode 100644 index 0000000000..7db107dee9 --- /dev/null +++ b/patches/server/0750-Add-fire-tick-delay-option.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: VytskaLT +Date: Wed, 22 Jun 2022 14:34:28 +0300 +Subject: [PATCH] Add fire-tick-delay option + + +diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java +index 065d6164b5c9d65d20e7790c607d77e9ad70dfef..0e5a47ab235d99e6cb1468905f791c2c59ac0082 100644 +--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java +@@ -171,7 +171,7 @@ public class FireBlock extends BaseFireBlock { + + @Override + protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { +- world.scheduleTick(pos, (Block) this, FireBlock.getFireTickDelay(world.random)); ++ world.scheduleTick(pos, (Block) this, FireBlock.getFireTickDelay(world)); // Paper - Add fire-tick-delay option + if (world.getGameRules().getBoolean(GameRules.RULE_DOFIRETICK)) { + if (!state.canSurvive(world, pos)) { + this.fireExtinguished(world, pos); // CraftBukkit - invalid place location +@@ -372,11 +372,11 @@ public class FireBlock extends BaseFireBlock { + protected void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, UseOnContext context) { + super.onPlace(iblockdata, world, blockposition, iblockdata1, flag, context); + // CraftBukkit end +- world.scheduleTick(blockposition, (Block) this, FireBlock.getFireTickDelay(world.random)); ++ world.scheduleTick(blockposition, (Block) this, FireBlock.getFireTickDelay(world)); // Paper - Add fire-tick-delay option + } + +- private static int getFireTickDelay(RandomSource random) { +- return 30 + random.nextInt(10); ++ private static int getFireTickDelay(Level world) { // Paper - Add fire-tick-delay option ++ return world.paperConfig().environment.fireTickDelay + world.random.nextInt(10); // Paper - Add fire-tick-delay option + } + + @Override diff --git a/patches/server/0751-Add-Moving-Piston-API.patch b/patches/server/0751-Add-Moving-Piston-API.patch new file mode 100644 index 0000000000..e3d3955822 --- /dev/null +++ b/patches/server/0751-Add-Moving-Piston-API.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sat, 4 Dec 2021 13:29:36 -0500 +Subject: [PATCH] Add Moving Piston API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java b/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java +index 25b759dee5ae2b311965f26ba311591199894be4..293ac0b658224fc0b3c2acdfc86eff3c8a9fdc04 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java +@@ -4,7 +4,7 @@ import net.minecraft.world.level.block.piston.PistonMovingBlockEntity; + import org.bukkit.Location; + import org.bukkit.World; + +-public class CraftMovingPiston extends CraftBlockEntityState { ++public class CraftMovingPiston extends CraftBlockEntityState implements io.papermc.paper.block.MovingPiston { // Paper - Add Moving Piston API + + public CraftMovingPiston(World world, PistonMovingBlockEntity tileEntity) { + super(world, tileEntity); +@@ -23,4 +23,26 @@ public class CraftMovingPiston extends CraftBlockEntityState -Date: Wed, 22 Jun 2022 14:34:28 +0300 -Subject: [PATCH] Add fire-tick-delay option - - -diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java -index 065d6164b5c9d65d20e7790c607d77e9ad70dfef..0e5a47ab235d99e6cb1468905f791c2c59ac0082 100644 ---- a/src/main/java/net/minecraft/world/level/block/FireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java -@@ -171,7 +171,7 @@ public class FireBlock extends BaseFireBlock { - - @Override - protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -- world.scheduleTick(pos, (Block) this, FireBlock.getFireTickDelay(world.random)); -+ world.scheduleTick(pos, (Block) this, FireBlock.getFireTickDelay(world)); // Paper - Add fire-tick-delay option - if (world.getGameRules().getBoolean(GameRules.RULE_DOFIRETICK)) { - if (!state.canSurvive(world, pos)) { - this.fireExtinguished(world, pos); // CraftBukkit - invalid place location -@@ -372,11 +372,11 @@ public class FireBlock extends BaseFireBlock { - protected void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, UseOnContext context) { - super.onPlace(iblockdata, world, blockposition, iblockdata1, flag, context); - // CraftBukkit end -- world.scheduleTick(blockposition, (Block) this, FireBlock.getFireTickDelay(world.random)); -+ world.scheduleTick(blockposition, (Block) this, FireBlock.getFireTickDelay(world)); // Paper - Add fire-tick-delay option - } - -- private static int getFireTickDelay(RandomSource random) { -- return 30 + random.nextInt(10); -+ private static int getFireTickDelay(Level world) { // Paper - Add fire-tick-delay option -+ return world.paperConfig().environment.fireTickDelay + world.random.nextInt(10); // Paper - Add fire-tick-delay option - } - - @Override diff --git a/patches/server/0752-Add-Moving-Piston-API.patch b/patches/server/0752-Add-Moving-Piston-API.patch deleted file mode 100644 index e3d3955822..0000000000 --- a/patches/server/0752-Add-Moving-Piston-API.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sat, 4 Dec 2021 13:29:36 -0500 -Subject: [PATCH] Add Moving Piston API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java b/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java -index 25b759dee5ae2b311965f26ba311591199894be4..293ac0b658224fc0b3c2acdfc86eff3c8a9fdc04 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java -@@ -4,7 +4,7 @@ import net.minecraft.world.level.block.piston.PistonMovingBlockEntity; - import org.bukkit.Location; - import org.bukkit.World; - --public class CraftMovingPiston extends CraftBlockEntityState { -+public class CraftMovingPiston extends CraftBlockEntityState implements io.papermc.paper.block.MovingPiston { // Paper - Add Moving Piston API - - public CraftMovingPiston(World world, PistonMovingBlockEntity tileEntity) { - super(world, tileEntity); -@@ -23,4 +23,26 @@ public class CraftMovingPiston extends CraftBlockEntityState +Date: Sat, 12 Feb 2022 23:42:48 +0800 +Subject: [PATCH] Ignore impossible spawn tick + + +diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java +index 1b6ec72f59504d2f420d6d5dcbed4d3b9115e3d8..7de66aa435dd36899b80f4ecc64480680e474d94 100644 +--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java ++++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java +@@ -84,6 +84,7 @@ public abstract class BaseSpawner { + } + + public void serverTick(ServerLevel world, BlockPos pos) { ++ if (spawnCount <= 0 || maxNearbyEntities <= 0) return; // Paper - Ignore impossible spawn tick + // Paper start - Configurable mob spawner tick rate + if (spawnDelay > 0 && --tickDelay > 0) return; + tickDelay = world.paperConfig().tickRates.mobSpawner; diff --git a/patches/server/0753-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch b/patches/server/0753-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch new file mode 100644 index 0000000000..2fe35c8b32 --- /dev/null +++ b/patches/server/0753-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 26 Oct 2022 13:13:12 -0700 +Subject: [PATCH] Fix EntityArgument and EntitySelectorParser permissions to + align with EntitySelector#checkPermissions + +Fixes where the user has permission for selectors but not their +suggestions, which especially matters when we force suggestions to +the server for this type + +diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java +index a327939abe2cce22747366051b6b7aaa2db3a8cc..3281ea4dca20d2bb22b2b1c6b9abb1329bc829c1 100644 +--- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java ++++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java +@@ -135,7 +135,12 @@ public class EntityArgument implements ArgumentType { + StringReader stringreader = new StringReader(suggestionsbuilder.getInput()); + + stringreader.setCursor(suggestionsbuilder.getStart()); +- EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, EntitySelectorParser.allowSelectors(icompletionprovider)); ++ // Paper start - Fix EntityArgument permissions ++ final boolean permission = object instanceof CommandSourceStack stack ++ ? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector") ++ : icompletionprovider.hasPermission(2); ++ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, permission); ++ // Paper end - Fix EntityArgument permissions + + try { + argumentparserselector.parse(); +diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java +index dd50a530439576f56f245ff0b7eb090f9f0c9180..9d31e29ec62f437e642ed60da69c4b106bd9e770 100644 +--- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java ++++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java +@@ -133,7 +133,7 @@ public class EntitySelectorParser { + boolean flag; + + if (source instanceof SharedSuggestionProvider icompletionprovider) { +- if (icompletionprovider.hasPermission(2)) { ++ if (source instanceof net.minecraft.commands.CommandSourceStack stack ? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector") : icompletionprovider.hasPermission(2)) { // Paper - Fix EntityArgument permissions + flag = true; + return flag; + } diff --git a/patches/server/0753-Ignore-impossible-spawn-tick.patch b/patches/server/0753-Ignore-impossible-spawn-tick.patch deleted file mode 100644 index ee2750f36d..0000000000 --- a/patches/server/0753-Ignore-impossible-spawn-tick.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dannyball710 -Date: Sat, 12 Feb 2022 23:42:48 +0800 -Subject: [PATCH] Ignore impossible spawn tick - - -diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java -index 1b6ec72f59504d2f420d6d5dcbed4d3b9115e3d8..7de66aa435dd36899b80f4ecc64480680e474d94 100644 ---- a/src/main/java/net/minecraft/world/level/BaseSpawner.java -+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java -@@ -84,6 +84,7 @@ public abstract class BaseSpawner { - } - - public void serverTick(ServerLevel world, BlockPos pos) { -+ if (spawnCount <= 0 || maxNearbyEntities <= 0) return; // Paper - Ignore impossible spawn tick - // Paper start - Configurable mob spawner tick rate - if (spawnDelay > 0 && --tickDelay > 0) return; - tickDelay = world.paperConfig().tickRates.mobSpawner; diff --git a/patches/server/0754-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch b/patches/server/0754-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch deleted file mode 100644 index 2fe35c8b32..0000000000 --- a/patches/server/0754-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 26 Oct 2022 13:13:12 -0700 -Subject: [PATCH] Fix EntityArgument and EntitySelectorParser permissions to - align with EntitySelector#checkPermissions - -Fixes where the user has permission for selectors but not their -suggestions, which especially matters when we force suggestions to -the server for this type - -diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java -index a327939abe2cce22747366051b6b7aaa2db3a8cc..3281ea4dca20d2bb22b2b1c6b9abb1329bc829c1 100644 ---- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java -+++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java -@@ -135,7 +135,12 @@ public class EntityArgument implements ArgumentType { - StringReader stringreader = new StringReader(suggestionsbuilder.getInput()); - - stringreader.setCursor(suggestionsbuilder.getStart()); -- EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, EntitySelectorParser.allowSelectors(icompletionprovider)); -+ // Paper start - Fix EntityArgument permissions -+ final boolean permission = object instanceof CommandSourceStack stack -+ ? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector") -+ : icompletionprovider.hasPermission(2); -+ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, permission); -+ // Paper end - Fix EntityArgument permissions - - try { - argumentparserselector.parse(); -diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java -index dd50a530439576f56f245ff0b7eb090f9f0c9180..9d31e29ec62f437e642ed60da69c4b106bd9e770 100644 ---- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java -+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java -@@ -133,7 +133,7 @@ public class EntitySelectorParser { - boolean flag; - - if (source instanceof SharedSuggestionProvider icompletionprovider) { -- if (icompletionprovider.hasPermission(2)) { -+ if (source instanceof net.minecraft.commands.CommandSourceStack stack ? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector") : icompletionprovider.hasPermission(2)) { // Paper - Fix EntityArgument permissions - flag = true; - return flag; - } diff --git a/patches/server/0754-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch b/patches/server/0754-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch new file mode 100644 index 0000000000..ab6fac6da3 --- /dev/null +++ b/patches/server/0754-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Denery +Date: Mon, 31 Oct 2022 14:20:52 +0300 +Subject: [PATCH] Fix EntityCombustEvent cancellation cant fully prevent + entities from being set on fire + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 619879bc0a05e16d450b4f7bb766b371e986193c..8aabd17178543eab0724a05226e4741ead85ea87 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3320,6 +3320,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + pluginManager.callEvent(entityCombustEvent); + if (!entityCombustEvent.isCancelled()) { + this.igniteForSeconds(entityCombustEvent.getDuration(), false); ++ // Paper start - fix EntityCombustEvent cancellation ++ } else { ++ this.setRemainingFireTicks(this.remainingFireTicks - 1); ++ // Paper end - fix EntityCombustEvent cancellation + } + // CraftBukkit end + } +diff --git a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java +index c8ca41cd81a72f9bff40f5c1b3bfc1189bf51f98..0cf4133849ed8ff6d4038cc41ede9d3645b31da1 100644 +--- a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java +@@ -145,6 +145,10 @@ public abstract class BaseFireBlock extends Block { + + if (!event.isCancelled()) { + entity.igniteForSeconds(event.getDuration(), false); ++ // Paper start - fix EntityCombustEvent cancellation ++ } else { ++ entity.setRemainingFireTicks(entity.getRemainingFireTicks() - 1); ++ // Paper end - fix EntityCombustEvent cancellation + } + // CraftBukkit end + } diff --git a/patches/server/0755-Add-PrePlayerAttackEntityEvent.patch b/patches/server/0755-Add-PrePlayerAttackEntityEvent.patch new file mode 100644 index 0000000000..5a925374e5 --- /dev/null +++ b/patches/server/0755-Add-PrePlayerAttackEntityEvent.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 18 Sep 2022 13:10:18 -0400 +Subject: [PATCH] Add PrePlayerAttackEntityEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java +index b8edbd23d547d7189ec64c5d3a8cd1d51859ce23..30e0a5fe3f9bd85d2b702c2c877c5682ed35d461 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -1222,8 +1222,17 @@ public abstract class Player extends LivingEntity { + } + + public void attack(Entity target) { +- if (target.isAttackable()) { +- if (!target.skipAttackInteraction(this)) { ++ // Paper start - PlayerAttackEntityEvent ++ boolean willAttack = target.isAttackable() && !target.skipAttackInteraction(this); // Vanilla logic ++ io.papermc.paper.event.player.PrePlayerAttackEntityEvent playerAttackEntityEvent = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent( ++ (org.bukkit.entity.Player) this.getBukkitEntity(), ++ target.getBukkitEntity(), ++ willAttack ++ ); ++ ++ if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable. ++ { ++ // Paper end - PlayerAttackEntityEvent + float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE); + ItemStack itemstack = this.getWeaponItem(); + DamageSource damagesource = (DamageSource) Optional.ofNullable(itemstack.getItem().getDamageSource(this)).orElse(this.damageSources().playerAttack(this)); diff --git a/patches/server/0755-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch b/patches/server/0755-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch deleted file mode 100644 index ab6fac6da3..0000000000 --- a/patches/server/0755-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Denery -Date: Mon, 31 Oct 2022 14:20:52 +0300 -Subject: [PATCH] Fix EntityCombustEvent cancellation cant fully prevent - entities from being set on fire - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 619879bc0a05e16d450b4f7bb766b371e986193c..8aabd17178543eab0724a05226e4741ead85ea87 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3320,6 +3320,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - pluginManager.callEvent(entityCombustEvent); - if (!entityCombustEvent.isCancelled()) { - this.igniteForSeconds(entityCombustEvent.getDuration(), false); -+ // Paper start - fix EntityCombustEvent cancellation -+ } else { -+ this.setRemainingFireTicks(this.remainingFireTicks - 1); -+ // Paper end - fix EntityCombustEvent cancellation - } - // CraftBukkit end - } -diff --git a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java -index c8ca41cd81a72f9bff40f5c1b3bfc1189bf51f98..0cf4133849ed8ff6d4038cc41ede9d3645b31da1 100644 ---- a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java -@@ -145,6 +145,10 @@ public abstract class BaseFireBlock extends Block { - - if (!event.isCancelled()) { - entity.igniteForSeconds(event.getDuration(), false); -+ // Paper start - fix EntityCombustEvent cancellation -+ } else { -+ entity.setRemainingFireTicks(entity.getRemainingFireTicks() - 1); -+ // Paper end - fix EntityCombustEvent cancellation - } - // CraftBukkit end - } diff --git a/patches/server/0756-Add-PrePlayerAttackEntityEvent.patch b/patches/server/0756-Add-PrePlayerAttackEntityEvent.patch deleted file mode 100644 index 5a925374e5..0000000000 --- a/patches/server/0756-Add-PrePlayerAttackEntityEvent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 18 Sep 2022 13:10:18 -0400 -Subject: [PATCH] Add PrePlayerAttackEntityEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index b8edbd23d547d7189ec64c5d3a8cd1d51859ce23..30e0a5fe3f9bd85d2b702c2c877c5682ed35d461 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1222,8 +1222,17 @@ public abstract class Player extends LivingEntity { - } - - public void attack(Entity target) { -- if (target.isAttackable()) { -- if (!target.skipAttackInteraction(this)) { -+ // Paper start - PlayerAttackEntityEvent -+ boolean willAttack = target.isAttackable() && !target.skipAttackInteraction(this); // Vanilla logic -+ io.papermc.paper.event.player.PrePlayerAttackEntityEvent playerAttackEntityEvent = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent( -+ (org.bukkit.entity.Player) this.getBukkitEntity(), -+ target.getBukkitEntity(), -+ willAttack -+ ); -+ -+ if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable. -+ { -+ // Paper end - PlayerAttackEntityEvent - float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE); - ItemStack itemstack = this.getWeaponItem(); - DamageSource damagesource = (DamageSource) Optional.ofNullable(itemstack.getItem().getDamageSource(this)).orElse(this.damageSources().playerAttack(this)); diff --git a/patches/server/0756-ensure-reset-EnderDragon-boss-event-name.patch b/patches/server/0756-ensure-reset-EnderDragon-boss-event-name.patch new file mode 100644 index 0000000000..4c5db1221b --- /dev/null +++ b/patches/server/0756-ensure-reset-EnderDragon-boss-event-name.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 12 Nov 2022 10:08:58 -0800 +Subject: [PATCH] ensure reset EnderDragon boss event name + +Fix MC-257487 + +diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +index bc6426c04ac1fd19949d587d2b7061895db0893b..39b1d6ee10d4a10ab4fb339621ca80f27d383324 100644 +--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java ++++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +@@ -74,6 +74,7 @@ public class EndDragonFight { + private static final int GATEWAY_DISTANCE = 96; + public static final int DRAGON_SPAWN_Y = 128; + private final Predicate validPlayer; ++ private static final Component DEFAULT_BOSS_EVENT_NAME = Component.translatable("entity.minecraft.ender_dragon"); // Paper - ensure reset EnderDragon boss event name + public final ServerBossEvent dragonEvent; + public final ServerLevel level; + private final BlockPos origin; +@@ -102,7 +103,7 @@ public class EndDragonFight { + } + + public EndDragonFight(ServerLevel world, long gatewaysSeed, EndDragonFight.Data data, BlockPos origin) { +- this.dragonEvent = (ServerBossEvent) (new ServerBossEvent(Component.translatable("entity.minecraft.ender_dragon"), BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS)).setPlayBossMusic(true).setCreateWorldFog(true); ++ this.dragonEvent = (ServerBossEvent) (new ServerBossEvent(DEFAULT_BOSS_EVENT_NAME, BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS)).setPlayBossMusic(true).setCreateWorldFog(true); // Paper - ensure reset EnderDragon boss event name + this.gateways = new ObjectArrayList(); + this.ticksSinceLastPlayerScan = 21; + this.skipArenaLoadedCheck = false; +@@ -506,6 +507,10 @@ public class EndDragonFight { + this.ticksSinceDragonSeen = 0; + if (dragon.hasCustomName()) { + this.dragonEvent.setName(dragon.getDisplayName()); ++ // Paper start - ensure reset EnderDragon boss event name ++ } else { ++ this.dragonEvent.setName(DEFAULT_BOSS_EVENT_NAME); ++ // Paper end - ensure reset EnderDragon boss event name + } + } + diff --git a/patches/server/0757-Add-Player-Warden-Warning-API.patch b/patches/server/0757-Add-Player-Warden-Warning-API.patch new file mode 100644 index 0000000000..2ce951d036 --- /dev/null +++ b/patches/server/0757-Add-Player-Warden-Warning-API.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dawon +Date: Sat, 15 Oct 2022 00:46:57 +0200 +Subject: [PATCH] Add Player Warden Warning API + +== AT == +public net.minecraft.server.level.ServerPlayer wardenSpawnTracker +public net.minecraft.world.entity.monster.warden.WardenSpawnTracker ticksSinceLastWarning +public net.minecraft.world.entity.monster.warden.WardenSpawnTracker cooldownTicks +public net.minecraft.world.entity.monster.warden.WardenSpawnTracker increaseWarningLevel()V + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 667796909ea6b56b93ec591aae1c393ec2f8940a..7ef67f0b5da392fa09a99d1213eefa373aad96b6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -3333,6 +3333,41 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + public void showElderGuardian(boolean silent) { + if (getHandle().connection != null) getHandle().connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, silent ? 0F : 1F)); + } ++ ++ @Override ++ public int getWardenWarningCooldown() { ++ return this.getHandle().wardenSpawnTracker.cooldownTicks; ++ } ++ ++ @Override ++ public void setWardenWarningCooldown(int cooldown) { ++ this.getHandle().wardenSpawnTracker.cooldownTicks = Math.max(cooldown, 0); ++ } ++ ++ @Override ++ public int getWardenTimeSinceLastWarning() { ++ return this.getHandle().wardenSpawnTracker.ticksSinceLastWarning; ++ } ++ ++ @Override ++ public void setWardenTimeSinceLastWarning(int time) { ++ this.getHandle().wardenSpawnTracker.ticksSinceLastWarning = time; ++ } ++ ++ @Override ++ public int getWardenWarningLevel() { ++ return this.getHandle().wardenSpawnTracker.getWarningLevel(); ++ } ++ ++ @Override ++ public void setWardenWarningLevel(int warningLevel) { ++ this.getHandle().wardenSpawnTracker.setWarningLevel(warningLevel); ++ } ++ ++ @Override ++ public void increaseWardenWarningLevel() { ++ this.getHandle().wardenSpawnTracker.increaseWarningLevel(); ++ } + // Paper end + + public Player.Spigot spigot() diff --git a/patches/server/0757-ensure-reset-EnderDragon-boss-event-name.patch b/patches/server/0757-ensure-reset-EnderDragon-boss-event-name.patch deleted file mode 100644 index 4c5db1221b..0000000000 --- a/patches/server/0757-ensure-reset-EnderDragon-boss-event-name.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 12 Nov 2022 10:08:58 -0800 -Subject: [PATCH] ensure reset EnderDragon boss event name - -Fix MC-257487 - -diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -index bc6426c04ac1fd19949d587d2b7061895db0893b..39b1d6ee10d4a10ab4fb339621ca80f27d383324 100644 ---- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -@@ -74,6 +74,7 @@ public class EndDragonFight { - private static final int GATEWAY_DISTANCE = 96; - public static final int DRAGON_SPAWN_Y = 128; - private final Predicate validPlayer; -+ private static final Component DEFAULT_BOSS_EVENT_NAME = Component.translatable("entity.minecraft.ender_dragon"); // Paper - ensure reset EnderDragon boss event name - public final ServerBossEvent dragonEvent; - public final ServerLevel level; - private final BlockPos origin; -@@ -102,7 +103,7 @@ public class EndDragonFight { - } - - public EndDragonFight(ServerLevel world, long gatewaysSeed, EndDragonFight.Data data, BlockPos origin) { -- this.dragonEvent = (ServerBossEvent) (new ServerBossEvent(Component.translatable("entity.minecraft.ender_dragon"), BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS)).setPlayBossMusic(true).setCreateWorldFog(true); -+ this.dragonEvent = (ServerBossEvent) (new ServerBossEvent(DEFAULT_BOSS_EVENT_NAME, BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS)).setPlayBossMusic(true).setCreateWorldFog(true); // Paper - ensure reset EnderDragon boss event name - this.gateways = new ObjectArrayList(); - this.ticksSinceLastPlayerScan = 21; - this.skipArenaLoadedCheck = false; -@@ -506,6 +507,10 @@ public class EndDragonFight { - this.ticksSinceDragonSeen = 0; - if (dragon.hasCustomName()) { - this.dragonEvent.setName(dragon.getDisplayName()); -+ // Paper start - ensure reset EnderDragon boss event name -+ } else { -+ this.dragonEvent.setName(DEFAULT_BOSS_EVENT_NAME); -+ // Paper end - ensure reset EnderDragon boss event name - } - } - diff --git a/patches/server/0758-Add-Player-Warden-Warning-API.patch b/patches/server/0758-Add-Player-Warden-Warning-API.patch deleted file mode 100644 index 2ce951d036..0000000000 --- a/patches/server/0758-Add-Player-Warden-Warning-API.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dawon -Date: Sat, 15 Oct 2022 00:46:57 +0200 -Subject: [PATCH] Add Player Warden Warning API - -== AT == -public net.minecraft.server.level.ServerPlayer wardenSpawnTracker -public net.minecraft.world.entity.monster.warden.WardenSpawnTracker ticksSinceLastWarning -public net.minecraft.world.entity.monster.warden.WardenSpawnTracker cooldownTicks -public net.minecraft.world.entity.monster.warden.WardenSpawnTracker increaseWarningLevel()V - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 667796909ea6b56b93ec591aae1c393ec2f8940a..7ef67f0b5da392fa09a99d1213eefa373aad96b6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3333,6 +3333,41 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - public void showElderGuardian(boolean silent) { - if (getHandle().connection != null) getHandle().connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, silent ? 0F : 1F)); - } -+ -+ @Override -+ public int getWardenWarningCooldown() { -+ return this.getHandle().wardenSpawnTracker.cooldownTicks; -+ } -+ -+ @Override -+ public void setWardenWarningCooldown(int cooldown) { -+ this.getHandle().wardenSpawnTracker.cooldownTicks = Math.max(cooldown, 0); -+ } -+ -+ @Override -+ public int getWardenTimeSinceLastWarning() { -+ return this.getHandle().wardenSpawnTracker.ticksSinceLastWarning; -+ } -+ -+ @Override -+ public void setWardenTimeSinceLastWarning(int time) { -+ this.getHandle().wardenSpawnTracker.ticksSinceLastWarning = time; -+ } -+ -+ @Override -+ public int getWardenWarningLevel() { -+ return this.getHandle().wardenSpawnTracker.getWarningLevel(); -+ } -+ -+ @Override -+ public void setWardenWarningLevel(int warningLevel) { -+ this.getHandle().wardenSpawnTracker.setWarningLevel(warningLevel); -+ } -+ -+ @Override -+ public void increaseWardenWarningLevel() { -+ this.getHandle().wardenSpawnTracker.increaseWarningLevel(); -+ } - // Paper end - - public Player.Spigot spigot() diff --git a/patches/server/0758-More-vanilla-friendly-methods-to-update-trades.patch b/patches/server/0758-More-vanilla-friendly-methods-to-update-trades.patch new file mode 100644 index 0000000000..b3901a0ae7 --- /dev/null +++ b/patches/server/0758-More-vanilla-friendly-methods-to-update-trades.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sun, 16 Oct 2022 16:12:49 +0200 +Subject: [PATCH] More vanilla friendly methods to update trades + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java +index f51078e4b9e6267fa43795d009f5d149b86acb5a..a573aa4d387ad3a4e1017890f2b50b83a3c27ff4 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java +@@ -895,6 +895,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + + @Override + protected void updateTrades() { ++ // Paper start - More vanilla friendly methods to update trades ++ updateTrades(TRADES_PER_LEVEL); ++ } ++ ++ public boolean updateTrades(int amount) { ++ // Paper end - More vanilla friendly methods to update trades + VillagerData villagerdata = this.getVillagerData(); + Int2ObjectMap int2objectmap; + +@@ -912,9 +918,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + if (avillagertrades_imerchantrecipeoption != null) { + MerchantOffers merchantrecipelist = this.getOffers(); + +- this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, 2); ++ this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, amount); // Paper - More vanilla friendly methods to update trades ++ return true; // Paper - More vanilla friendly methods to update trades + } + } ++ return false; // Paper - More vanilla friendly methods to update trades + } + + public void gossip(ServerLevel world, Villager villager, long time) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +index 45c44c46edee9f46b8e197f1f54ea2779bf1184c..8e895d6f84f7d84b219f2424909dd42e5f08dec4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +@@ -98,6 +98,34 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { + } + + // Paper start ++ @Override ++ public boolean increaseLevel(int amount) { ++ Preconditions.checkArgument(amount > 0, "Level earned must be positive"); ++ int supposedFinalLevel = this.getVillagerLevel() + amount; ++ Preconditions.checkArgument(net.minecraft.world.entity.npc.VillagerData.MIN_VILLAGER_LEVEL <= supposedFinalLevel && supposedFinalLevel <= net.minecraft.world.entity.npc.VillagerData.MAX_VILLAGER_LEVEL, ++ "Final level reached after the donation (%d) must be between [%d, %d]".formatted(supposedFinalLevel, net.minecraft.world.entity.npc.VillagerData.MIN_VILLAGER_LEVEL, net.minecraft.world.entity.npc.VillagerData.MAX_VILLAGER_LEVEL)); ++ ++ it.unimi.dsi.fastutil.ints.Int2ObjectMap trades = ++ net.minecraft.world.entity.npc.VillagerTrades.TRADES.get(this.getHandle().getVillagerData().getProfession()); ++ ++ if (trades == null || trades.isEmpty()) { ++ this.getHandle().setVillagerData(this.getHandle().getVillagerData().setLevel(supposedFinalLevel)); ++ return false; ++ } ++ ++ while (amount > 0) { ++ this.getHandle().increaseMerchantCareer(); ++ amount--; ++ } ++ return true; ++ } ++ ++ @Override ++ public boolean addTrades(int amount) { ++ Preconditions.checkArgument(amount > 0, "Number of trades unlocked must be positive"); ++ return this.getHandle().updateTrades(amount); ++ } ++ + @Override + public int getRestocksToday() { + return getHandle().numberOfRestocksToday; diff --git a/patches/server/0759-Add-paper-dumplisteners-command.patch b/patches/server/0759-Add-paper-dumplisteners-command.patch new file mode 100644 index 0000000000..aabb60033d --- /dev/null +++ b/patches/server/0759-Add-paper-dumplisteners-command.patch @@ -0,0 +1,197 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Tue, 25 Oct 2022 21:15:37 +0200 +Subject: [PATCH] Add /paper dumplisteners command + +Co-authored-by: TwoLeggedCat <80929284+TwoLeggedCat@users.noreply.github.com> + +diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java +index fd4f37711989431f997d77fb0917f8a9232ce53f..46bf42d5ea9e7b046f962531c5962d287cf44a41 100644 +--- a/src/main/java/io/papermc/paper/command/PaperCommand.java ++++ b/src/main/java/io/papermc/paper/command/PaperCommand.java +@@ -41,6 +41,7 @@ public final class PaperCommand extends Command { + commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); + commands.put(Set.of("dumpitem"), new DumpItemCommand()); + commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand()); ++ commands.put(Set.of("dumplisteners"), new DumpListenersCommand()); + + return commands.entrySet().stream() + .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) +diff --git a/src/main/java/io/papermc/paper/command/subcommands/DumpListenersCommand.java b/src/main/java/io/papermc/paper/command/subcommands/DumpListenersCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aa44d4685de3caee4131449bead7a084868ff976 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/subcommands/DumpListenersCommand.java +@@ -0,0 +1,172 @@ ++package io.papermc.paper.command.subcommands; ++ ++import com.destroystokyo.paper.util.SneakyThrow; ++import io.papermc.paper.command.PaperSubcommand; ++import java.io.File; ++import java.io.IOException; ++import java.io.PrintWriter; ++import java.lang.invoke.MethodHandle; ++import java.lang.invoke.MethodHandles; ++import java.lang.reflect.Field; ++import java.time.LocalDateTime; ++import java.time.format.DateTimeFormatter; ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.List; ++import java.util.Locale; ++import java.util.Set; ++import net.kyori.adventure.text.Component; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.Bukkit; ++import org.bukkit.command.CommandSender; ++import org.bukkit.event.HandlerList; ++import org.bukkit.plugin.Plugin; ++import org.bukkit.plugin.RegisteredListener; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++import static net.kyori.adventure.text.Component.newline; ++import static net.kyori.adventure.text.Component.space; ++import static net.kyori.adventure.text.Component.text; ++import static net.kyori.adventure.text.format.NamedTextColor.GRAY; ++import static net.kyori.adventure.text.format.NamedTextColor.GREEN; ++import static net.kyori.adventure.text.format.NamedTextColor.RED; ++import static net.kyori.adventure.text.format.NamedTextColor.WHITE; ++ ++@DefaultQualifier(NonNull.class) ++public final class DumpListenersCommand implements PaperSubcommand { ++ private static final MethodHandle EVENT_TYPES_HANDLE; ++ ++ static { ++ try { ++ final Field eventTypesField = HandlerList.class.getDeclaredField("EVENT_TYPES"); ++ eventTypesField.setAccessible(true); ++ EVENT_TYPES_HANDLE = MethodHandles.lookup().unreflectGetter(eventTypesField); ++ } catch (final ReflectiveOperationException e) { ++ throw new RuntimeException(e); ++ } ++ } ++ ++ @Override ++ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { ++ if (args.length >= 1 && args[0].equals("tofile")) { ++ this.dumpToFile(sender); ++ return true; ++ } ++ this.doDumpListeners(sender, args); ++ return true; ++ } ++ ++ private void dumpToFile(final CommandSender sender) { ++ final File file = new File("debug/listeners-" ++ + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt"); ++ file.getParentFile().mkdirs(); ++ try (final PrintWriter writer = new PrintWriter(file)) { ++ for (final String eventClass : eventClassNames()) { ++ final HandlerList handlers; ++ try { ++ handlers = (HandlerList) findClass(eventClass).getMethod("getHandlerList").invoke(null); ++ } catch (final ReflectiveOperationException e) { ++ continue; ++ } ++ if (handlers.getRegisteredListeners().length != 0) { ++ writer.println(eventClass); ++ } ++ for (final RegisteredListener registeredListener : handlers.getRegisteredListeners()) { ++ writer.println(" - " + registeredListener); ++ } ++ } ++ } catch (final IOException ex) { ++ throw new RuntimeException(ex); ++ } ++ sender.sendMessage(text("Dumped listeners to " + file, GREEN)); ++ } ++ ++ private void doDumpListeners(final CommandSender sender, final String[] args) { ++ if (args.length == 0) { ++ sender.sendMessage(text("Usage: /paper dumplisteners tofile|", RED)); ++ return; ++ } ++ ++ try { ++ final HandlerList handlers = (HandlerList) findClass(args[0]).getMethod("getHandlerList").invoke(null); ++ ++ if (handlers.getRegisteredListeners().length == 0) { ++ sender.sendMessage(text(args[0] + " does not have any registered listeners.")); ++ return; ++ } ++ ++ sender.sendMessage(text("Listeners for " + args[0] + ":")); ++ ++ for (final RegisteredListener listener : handlers.getRegisteredListeners()) { ++ final Component hoverText = text("Priority: " + listener.getPriority().name() + " (" + listener.getPriority().getSlot() + ")", WHITE) ++ .append(newline()) ++ .append(text("Listener: " + listener.getListener())) ++ .append(newline()) ++ .append(text("Executor: " + listener.getExecutor())) ++ .append(newline()) ++ .append(text("Ignoring cancelled: " + listener.isIgnoringCancelled())); ++ ++ sender.sendMessage(text(listener.getPlugin().getName(), GREEN) ++ .append(space()) ++ .append(text("(" + listener.getListener().getClass().getName() + ")", GRAY).hoverEvent(hoverText))); ++ } ++ ++ sender.sendMessage(text("Total listeners: " + handlers.getRegisteredListeners().length)); ++ ++ } catch (final ClassNotFoundException e) { ++ sender.sendMessage(text("Unable to find a class named '" + args[0] + "'. Make sure to use the fully qualified name.", RED)); ++ } catch (final NoSuchMethodException e) { ++ sender.sendMessage(text("Class '" + args[0] + "' does not have a valid getHandlerList method.", RED)); ++ } catch (final ReflectiveOperationException e) { ++ sender.sendMessage(text("Something went wrong, see the console for more details.", RED)); ++ MinecraftServer.LOGGER.warn("Error occurred while dumping listeners for class " + args[0], e); ++ } ++ } ++ ++ @Override ++ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { ++ return switch (args.length) { ++ case 0 -> suggestions(); ++ case 1 -> suggestions().stream() ++ .filter(clazz -> clazz.toLowerCase(Locale.ROOT).contains(args[0].toLowerCase(Locale.ROOT))) ++ .toList(); ++ default -> Collections.emptyList(); ++ }; ++ } ++ ++ private static List suggestions() { ++ final List ret = new ArrayList<>(); ++ ret.add("tofile"); ++ ret.addAll(eventClassNames()); ++ return ret; ++ } ++ ++ @SuppressWarnings("unchecked") ++ private static Set eventClassNames() { ++ try { ++ return (Set) EVENT_TYPES_HANDLE.invokeExact(); ++ } catch (final Throwable e) { ++ SneakyThrow.sneaky(e); ++ return Collections.emptySet(); // Unreachable ++ } ++ } ++ ++ private static Class findClass(final String className) throws ClassNotFoundException { ++ try { ++ return Class.forName(className); ++ } catch (final ClassNotFoundException ignore) { ++ for (final Plugin plugin : Bukkit.getServer().getPluginManager().getPlugins()) { ++ if (!plugin.isEnabled()) { ++ continue; ++ } ++ ++ try { ++ return Class.forName(className, false, plugin.getClass().getClassLoader()); ++ } catch (final ClassNotFoundException ignore0) { ++ } ++ } ++ } ++ throw new ClassNotFoundException(className); ++ } ++} diff --git a/patches/server/0759-More-vanilla-friendly-methods-to-update-trades.patch b/patches/server/0759-More-vanilla-friendly-methods-to-update-trades.patch deleted file mode 100644 index b3901a0ae7..0000000000 --- a/patches/server/0759-More-vanilla-friendly-methods-to-update-trades.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Sun, 16 Oct 2022 16:12:49 +0200 -Subject: [PATCH] More vanilla friendly methods to update trades - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index f51078e4b9e6267fa43795d009f5d149b86acb5a..a573aa4d387ad3a4e1017890f2b50b83a3c27ff4 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -895,6 +895,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - - @Override - protected void updateTrades() { -+ // Paper start - More vanilla friendly methods to update trades -+ updateTrades(TRADES_PER_LEVEL); -+ } -+ -+ public boolean updateTrades(int amount) { -+ // Paper end - More vanilla friendly methods to update trades - VillagerData villagerdata = this.getVillagerData(); - Int2ObjectMap int2objectmap; - -@@ -912,9 +918,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - if (avillagertrades_imerchantrecipeoption != null) { - MerchantOffers merchantrecipelist = this.getOffers(); - -- this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, 2); -+ this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, amount); // Paper - More vanilla friendly methods to update trades -+ return true; // Paper - More vanilla friendly methods to update trades - } - } -+ return false; // Paper - More vanilla friendly methods to update trades - } - - public void gossip(ServerLevel world, Villager villager, long time) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -index 45c44c46edee9f46b8e197f1f54ea2779bf1184c..8e895d6f84f7d84b219f2424909dd42e5f08dec4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -@@ -98,6 +98,34 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { - } - - // Paper start -+ @Override -+ public boolean increaseLevel(int amount) { -+ Preconditions.checkArgument(amount > 0, "Level earned must be positive"); -+ int supposedFinalLevel = this.getVillagerLevel() + amount; -+ Preconditions.checkArgument(net.minecraft.world.entity.npc.VillagerData.MIN_VILLAGER_LEVEL <= supposedFinalLevel && supposedFinalLevel <= net.minecraft.world.entity.npc.VillagerData.MAX_VILLAGER_LEVEL, -+ "Final level reached after the donation (%d) must be between [%d, %d]".formatted(supposedFinalLevel, net.minecraft.world.entity.npc.VillagerData.MIN_VILLAGER_LEVEL, net.minecraft.world.entity.npc.VillagerData.MAX_VILLAGER_LEVEL)); -+ -+ it.unimi.dsi.fastutil.ints.Int2ObjectMap trades = -+ net.minecraft.world.entity.npc.VillagerTrades.TRADES.get(this.getHandle().getVillagerData().getProfession()); -+ -+ if (trades == null || trades.isEmpty()) { -+ this.getHandle().setVillagerData(this.getHandle().getVillagerData().setLevel(supposedFinalLevel)); -+ return false; -+ } -+ -+ while (amount > 0) { -+ this.getHandle().increaseMerchantCareer(); -+ amount--; -+ } -+ return true; -+ } -+ -+ @Override -+ public boolean addTrades(int amount) { -+ Preconditions.checkArgument(amount > 0, "Number of trades unlocked must be positive"); -+ return this.getHandle().updateTrades(amount); -+ } -+ - @Override - public int getRestocksToday() { - return getHandle().numberOfRestocksToday; diff --git a/patches/server/0760-Add-paper-dumplisteners-command.patch b/patches/server/0760-Add-paper-dumplisteners-command.patch deleted file mode 100644 index aabb60033d..0000000000 --- a/patches/server/0760-Add-paper-dumplisteners-command.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Tue, 25 Oct 2022 21:15:37 +0200 -Subject: [PATCH] Add /paper dumplisteners command - -Co-authored-by: TwoLeggedCat <80929284+TwoLeggedCat@users.noreply.github.com> - -diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java -index fd4f37711989431f997d77fb0917f8a9232ce53f..46bf42d5ea9e7b046f962531c5962d287cf44a41 100644 ---- a/src/main/java/io/papermc/paper/command/PaperCommand.java -+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java -@@ -41,6 +41,7 @@ public final class PaperCommand extends Command { - commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); - commands.put(Set.of("dumpitem"), new DumpItemCommand()); - commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand()); -+ commands.put(Set.of("dumplisteners"), new DumpListenersCommand()); - - return commands.entrySet().stream() - .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) -diff --git a/src/main/java/io/papermc/paper/command/subcommands/DumpListenersCommand.java b/src/main/java/io/papermc/paper/command/subcommands/DumpListenersCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aa44d4685de3caee4131449bead7a084868ff976 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/DumpListenersCommand.java -@@ -0,0 +1,172 @@ -+package io.papermc.paper.command.subcommands; -+ -+import com.destroystokyo.paper.util.SneakyThrow; -+import io.papermc.paper.command.PaperSubcommand; -+import java.io.File; -+import java.io.IOException; -+import java.io.PrintWriter; -+import java.lang.invoke.MethodHandle; -+import java.lang.invoke.MethodHandles; -+import java.lang.reflect.Field; -+import java.time.LocalDateTime; -+import java.time.format.DateTimeFormatter; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.List; -+import java.util.Locale; -+import java.util.Set; -+import net.kyori.adventure.text.Component; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.Bukkit; -+import org.bukkit.command.CommandSender; -+import org.bukkit.event.HandlerList; -+import org.bukkit.plugin.Plugin; -+import org.bukkit.plugin.RegisteredListener; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+import static net.kyori.adventure.text.Component.newline; -+import static net.kyori.adventure.text.Component.space; -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.GRAY; -+import static net.kyori.adventure.text.format.NamedTextColor.GREEN; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+import static net.kyori.adventure.text.format.NamedTextColor.WHITE; -+ -+@DefaultQualifier(NonNull.class) -+public final class DumpListenersCommand implements PaperSubcommand { -+ private static final MethodHandle EVENT_TYPES_HANDLE; -+ -+ static { -+ try { -+ final Field eventTypesField = HandlerList.class.getDeclaredField("EVENT_TYPES"); -+ eventTypesField.setAccessible(true); -+ EVENT_TYPES_HANDLE = MethodHandles.lookup().unreflectGetter(eventTypesField); -+ } catch (final ReflectiveOperationException e) { -+ throw new RuntimeException(e); -+ } -+ } -+ -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ if (args.length >= 1 && args[0].equals("tofile")) { -+ this.dumpToFile(sender); -+ return true; -+ } -+ this.doDumpListeners(sender, args); -+ return true; -+ } -+ -+ private void dumpToFile(final CommandSender sender) { -+ final File file = new File("debug/listeners-" -+ + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt"); -+ file.getParentFile().mkdirs(); -+ try (final PrintWriter writer = new PrintWriter(file)) { -+ for (final String eventClass : eventClassNames()) { -+ final HandlerList handlers; -+ try { -+ handlers = (HandlerList) findClass(eventClass).getMethod("getHandlerList").invoke(null); -+ } catch (final ReflectiveOperationException e) { -+ continue; -+ } -+ if (handlers.getRegisteredListeners().length != 0) { -+ writer.println(eventClass); -+ } -+ for (final RegisteredListener registeredListener : handlers.getRegisteredListeners()) { -+ writer.println(" - " + registeredListener); -+ } -+ } -+ } catch (final IOException ex) { -+ throw new RuntimeException(ex); -+ } -+ sender.sendMessage(text("Dumped listeners to " + file, GREEN)); -+ } -+ -+ private void doDumpListeners(final CommandSender sender, final String[] args) { -+ if (args.length == 0) { -+ sender.sendMessage(text("Usage: /paper dumplisteners tofile|", RED)); -+ return; -+ } -+ -+ try { -+ final HandlerList handlers = (HandlerList) findClass(args[0]).getMethod("getHandlerList").invoke(null); -+ -+ if (handlers.getRegisteredListeners().length == 0) { -+ sender.sendMessage(text(args[0] + " does not have any registered listeners.")); -+ return; -+ } -+ -+ sender.sendMessage(text("Listeners for " + args[0] + ":")); -+ -+ for (final RegisteredListener listener : handlers.getRegisteredListeners()) { -+ final Component hoverText = text("Priority: " + listener.getPriority().name() + " (" + listener.getPriority().getSlot() + ")", WHITE) -+ .append(newline()) -+ .append(text("Listener: " + listener.getListener())) -+ .append(newline()) -+ .append(text("Executor: " + listener.getExecutor())) -+ .append(newline()) -+ .append(text("Ignoring cancelled: " + listener.isIgnoringCancelled())); -+ -+ sender.sendMessage(text(listener.getPlugin().getName(), GREEN) -+ .append(space()) -+ .append(text("(" + listener.getListener().getClass().getName() + ")", GRAY).hoverEvent(hoverText))); -+ } -+ -+ sender.sendMessage(text("Total listeners: " + handlers.getRegisteredListeners().length)); -+ -+ } catch (final ClassNotFoundException e) { -+ sender.sendMessage(text("Unable to find a class named '" + args[0] + "'. Make sure to use the fully qualified name.", RED)); -+ } catch (final NoSuchMethodException e) { -+ sender.sendMessage(text("Class '" + args[0] + "' does not have a valid getHandlerList method.", RED)); -+ } catch (final ReflectiveOperationException e) { -+ sender.sendMessage(text("Something went wrong, see the console for more details.", RED)); -+ MinecraftServer.LOGGER.warn("Error occurred while dumping listeners for class " + args[0], e); -+ } -+ } -+ -+ @Override -+ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { -+ return switch (args.length) { -+ case 0 -> suggestions(); -+ case 1 -> suggestions().stream() -+ .filter(clazz -> clazz.toLowerCase(Locale.ROOT).contains(args[0].toLowerCase(Locale.ROOT))) -+ .toList(); -+ default -> Collections.emptyList(); -+ }; -+ } -+ -+ private static List suggestions() { -+ final List ret = new ArrayList<>(); -+ ret.add("tofile"); -+ ret.addAll(eventClassNames()); -+ return ret; -+ } -+ -+ @SuppressWarnings("unchecked") -+ private static Set eventClassNames() { -+ try { -+ return (Set) EVENT_TYPES_HANDLE.invokeExact(); -+ } catch (final Throwable e) { -+ SneakyThrow.sneaky(e); -+ return Collections.emptySet(); // Unreachable -+ } -+ } -+ -+ private static Class findClass(final String className) throws ClassNotFoundException { -+ try { -+ return Class.forName(className); -+ } catch (final ClassNotFoundException ignore) { -+ for (final Plugin plugin : Bukkit.getServer().getPluginManager().getPlugins()) { -+ if (!plugin.isEnabled()) { -+ continue; -+ } -+ -+ try { -+ return Class.forName(className, false, plugin.getClass().getClassLoader()); -+ } catch (final ClassNotFoundException ignore0) { -+ } -+ } -+ } -+ throw new ClassNotFoundException(className); -+ } -+} diff --git a/patches/server/0760-check-global-player-list-where-appropriate.patch b/patches/server/0760-check-global-player-list-where-appropriate.patch new file mode 100644 index 0000000000..393c169165 --- /dev/null +++ b/patches/server/0760-check-global-player-list-where-appropriate.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 22 Nov 2022 13:16:01 -0800 +Subject: [PATCH] check global player list where appropriate + +Makes certain entities check all players when searching for a player +instead of just checking players in their world. + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 45e61a08152517a61260e662764d8bb0335537e3..b81d814619e4175f42aee397811b07cae420c2e8 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2353,4 +2353,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + entity.updateDynamicGameEventListener(DynamicGameEventListener::move); + } + } ++ ++ // Paper start - check global player list where appropriate ++ @Override ++ @Nullable ++ public Player getGlobalPlayerByUUID(UUID uuid) { ++ return this.server.getPlayerList().getPlayer(uuid); ++ } ++ // Paper end - check global player list where appropriate + } +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index b367f6e329f44801c6f0d34f447497093d86ae3b..5330f6315cecfa6afd04b711a5b8656717cb5ede 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3865,7 +3865,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + public void onItemPickup(ItemEntity item) { +- Entity entity = item.getOwner(); ++ Entity entity = item.thrower != null ? this.level().getGlobalPlayerByUUID(item.thrower) : null; // Paper - check global player list where appropriate + + if (entity instanceof ServerPlayer) { + CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer) entity, item.getItem(), this); +diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +index 533cb2eff3d56e7e8a70aba5e1047250e192bf2c..18c19e4b675000aacb74344909fc104964231008 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -262,7 +262,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + entityvillager.finalizeSpawn(world, world.getCurrentDifficultyAt(entityvillager.blockPosition()), EntitySpawnReason.CONVERSION, (SpawnGroupData) null); + entityvillager.refreshBrain(world); + if (this.conversionStarter != null) { +- Player entityhuman = world.getPlayerByUUID(this.conversionStarter); ++ Player entityhuman = world.getGlobalPlayerByUUID(this.conversionStarter); // Paper - check global player list where appropriate + + if (entityhuman instanceof ServerPlayer) { + CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer) entityhuman, this, entityvillager); +diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java +index dac8305f1c897e6f82a2dde67c5b1b6b8b649b19..e185a33b5b1f8e8e0a0e666b24ba3e9186a8a7ff 100644 +--- a/src/main/java/net/minecraft/world/level/EntityGetter.java ++++ b/src/main/java/net/minecraft/world/level/EntityGetter.java +@@ -165,4 +165,11 @@ public interface EntityGetter { + + return null; + } ++ ++ // Paper start - check global player list where appropriate ++ @Nullable ++ default Player getGlobalPlayerByUUID(UUID uuid) { ++ return this.getPlayerByUUID(uuid); ++ } ++ // Paper end - check global player list where appropriate + } +diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java +index ea53c25c350c0cf8e0360ea409cd1f69a62054a8..275721d8b3d653b38af505dde30396c0b7b6a3da 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java +@@ -105,6 +105,13 @@ public class SculkShriekerBlockEntity extends BlockEntity implements GameEventLi + + @Nullable + public static ServerPlayer tryGetPlayer(@Nullable Entity entity) { ++ // Paper start - check global player list where appropriate; ensure level is the same for sculk events ++ final ServerPlayer player = tryGetPlayer0(entity); ++ return player != null && player.level() == entity.level() ? player : null; ++ } ++ @Nullable ++ private static ServerPlayer tryGetPlayer0(@Nullable Entity entity) { ++ // Paper end - check global player list where appropriate + if (entity instanceof ServerPlayer) { + return (ServerPlayer)entity; + } else { diff --git a/patches/server/0761-Fix-async-entity-add-due-to-fungus-trees.patch b/patches/server/0761-Fix-async-entity-add-due-to-fungus-trees.patch new file mode 100644 index 0000000000..009feeb37a --- /dev/null +++ b/patches/server/0761-Fix-async-entity-add-due-to-fungus-trees.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 18 Mar 2022 21:30:00 -0700 +Subject: [PATCH] Fix async entity add due to fungus trees + + +diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java +index 5bf438bb58833c1df3620e82d3d2b90207366372..2e72e92762877b28dd908711671e1dfb933de9b0 100644 +--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java ++++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java +@@ -237,6 +237,7 @@ public class WorldGenRegion implements WorldGenLevel { + if (iblockdata.isAir()) { + return false; + } else { ++ if (drop) LOGGER.warn("Potential async entity add during worldgen", new Throwable()); // Paper - Fix async entity add due to fungus trees; log when this happens + if (false) { // CraftBukkit - SPIGOT-6833: Do not drop during world generation + BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null; + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +index a93a879117ee1eb06842242aa03f757a4a676946..4c234e887c42b27754ed8f05f2000d9309274427 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +@@ -261,10 +261,10 @@ public abstract class CraftRegionAccessor implements RegionAccessor { + ((ChorusFlowerBlock) Blocks.CHORUS_FLOWER).generatePlant(access, pos, random, 8); + return true; + case CRIMSON_FUNGUS: +- gen = TreeFeatures.CRIMSON_FUNGUS_PLANTED; ++ gen = this.isNormalWorld() ? TreeFeatures.CRIMSON_FUNGUS_PLANTED : TreeFeatures.CRIMSON_FUNGUS; // Paper - Fix async entity add due to fungus trees; if world gen, don't use planted version + break; + case WARPED_FUNGUS: +- gen = TreeFeatures.WARPED_FUNGUS_PLANTED; ++ gen = this.isNormalWorld() ? TreeFeatures.WARPED_FUNGUS_PLANTED : TreeFeatures.WARPED_FUNGUS; // Paper - Fix async entity add due to fungus trees; if world gen, don't use planted version + break; + case AZALEA: + gen = TreeFeatures.AZALEA_TREE; diff --git a/patches/server/0761-check-global-player-list-where-appropriate.patch b/patches/server/0761-check-global-player-list-where-appropriate.patch deleted file mode 100644 index e96a666062..0000000000 --- a/patches/server/0761-check-global-player-list-where-appropriate.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 22 Nov 2022 13:16:01 -0800 -Subject: [PATCH] check global player list where appropriate - -Makes certain entities check all players when searching for a player -instead of just checking players in their world. - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 18d39f4a8b1b15960a9b8351d46a62bea848f9c8..79acbaf880d5f47efd210627a60ce1e930b63e39 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2383,4 +2383,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - entity.updateDynamicGameEventListener(DynamicGameEventListener::move); - } - } -+ -+ // Paper start - check global player list where appropriate -+ @Override -+ @Nullable -+ public Player getGlobalPlayerByUUID(UUID uuid) { -+ return this.server.getPlayerList().getPlayer(uuid); -+ } -+ // Paper end - check global player list where appropriate - } -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 7705c791bfbb386f0b9f326c4b0ee0057ed0e6f5..2c343617f9467bbef03f4d131ce94b1f1a090a80 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3867,7 +3867,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - public void onItemPickup(ItemEntity item) { -- Entity entity = item.getOwner(); -+ Entity entity = item.thrower != null ? this.level().getGlobalPlayerByUUID(item.thrower) : null; // Paper - check global player list where appropriate - - if (entity instanceof ServerPlayer) { - CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer) entity, item.getItem(), this); -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index 533cb2eff3d56e7e8a70aba5e1047250e192bf2c..18c19e4b675000aacb74344909fc104964231008 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -262,7 +262,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - entityvillager.finalizeSpawn(world, world.getCurrentDifficultyAt(entityvillager.blockPosition()), EntitySpawnReason.CONVERSION, (SpawnGroupData) null); - entityvillager.refreshBrain(world); - if (this.conversionStarter != null) { -- Player entityhuman = world.getPlayerByUUID(this.conversionStarter); -+ Player entityhuman = world.getGlobalPlayerByUUID(this.conversionStarter); // Paper - check global player list where appropriate - - if (entityhuman instanceof ServerPlayer) { - CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer) entityhuman, this, entityvillager); -diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java -index dac8305f1c897e6f82a2dde67c5b1b6b8b649b19..e185a33b5b1f8e8e0a0e666b24ba3e9186a8a7ff 100644 ---- a/src/main/java/net/minecraft/world/level/EntityGetter.java -+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java -@@ -165,4 +165,11 @@ public interface EntityGetter { - - return null; - } -+ -+ // Paper start - check global player list where appropriate -+ @Nullable -+ default Player getGlobalPlayerByUUID(UUID uuid) { -+ return this.getPlayerByUUID(uuid); -+ } -+ // Paper end - check global player list where appropriate - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java -index ea53c25c350c0cf8e0360ea409cd1f69a62054a8..275721d8b3d653b38af505dde30396c0b7b6a3da 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java -@@ -105,6 +105,13 @@ public class SculkShriekerBlockEntity extends BlockEntity implements GameEventLi - - @Nullable - public static ServerPlayer tryGetPlayer(@Nullable Entity entity) { -+ // Paper start - check global player list where appropriate; ensure level is the same for sculk events -+ final ServerPlayer player = tryGetPlayer0(entity); -+ return player != null && player.level() == entity.level() ? player : null; -+ } -+ @Nullable -+ private static ServerPlayer tryGetPlayer0(@Nullable Entity entity) { -+ // Paper end - check global player list where appropriate - if (entity instanceof ServerPlayer) { - return (ServerPlayer)entity; - } else { diff --git a/patches/server/0762-Fix-async-entity-add-due-to-fungus-trees.patch b/patches/server/0762-Fix-async-entity-add-due-to-fungus-trees.patch deleted file mode 100644 index 009feeb37a..0000000000 --- a/patches/server/0762-Fix-async-entity-add-due-to-fungus-trees.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 18 Mar 2022 21:30:00 -0700 -Subject: [PATCH] Fix async entity add due to fungus trees - - -diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index 5bf438bb58833c1df3620e82d3d2b90207366372..2e72e92762877b28dd908711671e1dfb933de9b0 100644 ---- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java -+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -237,6 +237,7 @@ public class WorldGenRegion implements WorldGenLevel { - if (iblockdata.isAir()) { - return false; - } else { -+ if (drop) LOGGER.warn("Potential async entity add during worldgen", new Throwable()); // Paper - Fix async entity add due to fungus trees; log when this happens - if (false) { // CraftBukkit - SPIGOT-6833: Do not drop during world generation - BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null; - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -index a93a879117ee1eb06842242aa03f757a4a676946..4c234e887c42b27754ed8f05f2000d9309274427 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -@@ -261,10 +261,10 @@ public abstract class CraftRegionAccessor implements RegionAccessor { - ((ChorusFlowerBlock) Blocks.CHORUS_FLOWER).generatePlant(access, pos, random, 8); - return true; - case CRIMSON_FUNGUS: -- gen = TreeFeatures.CRIMSON_FUNGUS_PLANTED; -+ gen = this.isNormalWorld() ? TreeFeatures.CRIMSON_FUNGUS_PLANTED : TreeFeatures.CRIMSON_FUNGUS; // Paper - Fix async entity add due to fungus trees; if world gen, don't use planted version - break; - case WARPED_FUNGUS: -- gen = TreeFeatures.WARPED_FUNGUS_PLANTED; -+ gen = this.isNormalWorld() ? TreeFeatures.WARPED_FUNGUS_PLANTED : TreeFeatures.WARPED_FUNGUS; // Paper - Fix async entity add due to fungus trees; if world gen, don't use planted version - break; - case AZALEA: - gen = TreeFeatures.AZALEA_TREE; diff --git a/patches/server/0762-ItemStack-damage-API.patch b/patches/server/0762-ItemStack-damage-API.patch new file mode 100644 index 0000000000..55e7f06af1 --- /dev/null +++ b/patches/server/0762-ItemStack-damage-API.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 8 May 2022 13:35:45 -0700 +Subject: [PATCH] ItemStack damage API + +Adds methods notify clients about item breaks and +to simulate damage done to an itemstack and all +the logic associated with damaging them + +== AT == +public net.minecraft.world.entity.LivingEntity entityEventForEquipmentBreak(Lnet/minecraft/world/entity/EquipmentSlot;)B + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index bcb3a45166e5dd75dd727adf92304b3a75399c8d..90a55f00c36903d52630c51bf69322973a2b5274 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -693,8 +693,13 @@ public final class ItemStack implements DataComponentHolder { + } + + public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent ++ // Paper start - add force boolean overload ++ this.hurtAndBreak(amount, world, player, breakCallback, false); ++ } ++ public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback, boolean force) { // Paper - Add EntityDamageItemEvent ++ // Paper end + int originalDamage = amount; // Paper - Expand PlayerItemDamageEvent +- int j = this.processDurabilityChange(amount, world, player); ++ int j = this.processDurabilityChange(amount, world, player, force); // Paper + // CraftBukkit start + if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent + PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j, originalDamage); // Paper - Add EntityDamageItemEvent +@@ -726,7 +731,12 @@ public final class ItemStack implements DataComponentHolder { + } + + private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable LivingEntity player) { // Paper - Add EntityDamageItemEvent +- return !this.isDamageableItem() ? 0 : (player instanceof ServerPlayer && player.hasInfiniteMaterials() ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage)); // Paper - Add EntityDamageItemEvent ++ // Paper start - itemstack damage api ++ return processDurabilityChange(baseDamage, world, player, false); ++ } ++ private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable LivingEntity player, boolean force) { ++ return !this.isDamageableItem() ? 0 : (player instanceof ServerPlayer && player.hasInfiniteMaterials() && !force ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage)); // Paper - Add EntityDamageItemEvent ++ // Paper end - itemstack damage api + } + + private void applyDamage(int damage, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent +@@ -766,6 +776,11 @@ public final class ItemStack implements DataComponentHolder { + } + + public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot) { ++ // Paper start - add param to skip infinite mats check ++ this.hurtAndBreak(amount, entity, slot, false); ++ } ++ public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot, boolean force) { ++ // Paper end - add param to skip infinite mats check + Level world = entity.level(); + + if (world instanceof ServerLevel worldserver) { +@@ -778,8 +793,8 @@ public final class ItemStack implements DataComponentHolder { + } + + this.hurtAndBreak(amount, worldserver, entity, (item) -> { // Paper - Add EntityDamageItemEvent +- entity.onEquippedItemBroken(item, slot); +- }); ++ if (slot != null) entity.onEquippedItemBroken(item, slot); // Paper - itemstack damage API - do not process entity related callbacks when damaging from API ++ }, force); // Paper - itemstack damage API + } + + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 4fa19ddb1414282020e118eea298d57d2bf42754..1ceaa081231a617bd87331b308c24d9c7a8dcf2b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1154,4 +1154,48 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + this.getHandle().knockback(strength, directionX, directionZ); + }; + // Paper end - knockback API ++ ++ // Paper start - ItemStack damage API ++ public void broadcastSlotBreak(final org.bukkit.inventory.EquipmentSlot slot) { ++ this.getHandle().level().broadcastEntityEvent(this.getHandle(), net.minecraft.world.entity.LivingEntity.entityEventForEquipmentBreak(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot))); ++ } ++ ++ @Override ++ public void broadcastSlotBreak(final org.bukkit.inventory.EquipmentSlot slot, final Collection players) { ++ if (players.isEmpty()) { ++ return; ++ } ++ final net.minecraft.network.protocol.game.ClientboundEntityEventPacket packet = new net.minecraft.network.protocol.game.ClientboundEntityEventPacket( ++ this.getHandle(), ++ net.minecraft.world.entity.LivingEntity.entityEventForEquipmentBreak(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)) ++ ); ++ players.forEach(player -> ((CraftPlayer) player).getHandle().connection.send(packet)); ++ } ++ ++ @Override ++ public ItemStack damageItemStack(ItemStack stack, final int amount) { ++ final net.minecraft.world.item.ItemStack nmsStack; ++ if (stack instanceof final CraftItemStack craftItemStack) { ++ if (craftItemStack.handle == null || craftItemStack.handle.isEmpty()) { ++ return stack; ++ } ++ nmsStack = craftItemStack.handle; ++ } else { ++ nmsStack = CraftItemStack.asNMSCopy(stack); ++ stack = CraftItemStack.asCraftMirror(nmsStack); // mirror to capture changes in hurt logic & events ++ } ++ this.damageItemStack0(nmsStack, amount, null); ++ return stack; ++ } ++ ++ @Override ++ public void damageItemStack(final org.bukkit.inventory.EquipmentSlot slot, final int amount) { ++ final net.minecraft.world.entity.EquipmentSlot nmsSlot = org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot); ++ this.damageItemStack0(this.getHandle().getItemBySlot(nmsSlot), amount, nmsSlot); ++ } ++ ++ private void damageItemStack0(final net.minecraft.world.item.ItemStack nmsStack, final int amount, final net.minecraft.world.entity.EquipmentSlot slot) { ++ nmsStack.hurtAndBreak(amount, this.getHandle(), slot, true); ++ } ++ // Paper end - ItemStack damage API + } diff --git a/patches/server/0763-Friction-API.patch b/patches/server/0763-Friction-API.patch new file mode 100644 index 0000000000..25f88d845f --- /dev/null +++ b/patches/server/0763-Friction-API.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Wed, 15 Sep 2021 20:44:22 +0200 +Subject: [PATCH] Friction API + + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 5330f6315cecfa6afd04b711a5b8656717cb5ede..8b0a764984f886b711cb337a7f70608167916bf3 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -296,6 +296,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + public boolean bukkitPickUpLoot; + public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper + public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event ++ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API + + @Override + public float getBukkitYaw() { +@@ -722,7 +723,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + public boolean shouldDiscardFriction() { +- return this.discardFriction; ++ return !this.frictionState.toBooleanOrElse(!this.discardFriction); // Paper - Friction API + } + + public void setDiscardFriction(boolean noDrag) { +@@ -796,6 +797,11 @@ public abstract class LivingEntity extends Entity implements Attackable { + + @Override + public void addAdditionalSaveData(CompoundTag nbt) { ++ // Paper start - Friction API ++ if (this.frictionState != net.kyori.adventure.util.TriState.NOT_SET) { ++ nbt.putString("Paper.FrictionState", this.frictionState.toString()); ++ } ++ // Paper end - Friction API + nbt.putFloat("Health", this.getHealth()); + nbt.putShort("HurtTime", (short) this.hurtTime); + nbt.putInt("HurtByTimestamp", this.lastHurtByMobTimestamp); +@@ -839,6 +845,16 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + this.internalSetAbsorptionAmount(absorptionAmount); + // Paper end - Check for NaN ++ // Paper start - Friction API ++ if (nbt.contains("Paper.FrictionState")) { ++ String fs = nbt.getString("Paper.FrictionState"); ++ try { ++ frictionState = net.kyori.adventure.util.TriState.valueOf(fs); ++ } catch (Exception ignored) { ++ LOGGER.error("Unknown friction state " + fs + " for " + this); ++ } ++ } ++ // Paper end - Friction API + if (nbt.contains("attributes", 9) && this.level() != null && !this.level().isClientSide) { + this.getAttributes().load(nbt.getList("attributes", 10)); + } +diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +index aa41c4cf8d3ae291c4147118c96190ff0bb807b2..e83a705f54063a17fc69a22683333aacad5a43ce 100644 +--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java ++++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +@@ -63,6 +63,7 @@ public class ItemEntity extends Entity implements TraceableEntity { + private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit + public boolean canMobPickup = true; // Paper - Item#canEntityPickup + private int despawnRate = -1; // Paper - Alternative item-despawn-rate ++ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API + + public ItemEntity(EntityType type, Level world) { + super(type, world); +@@ -186,7 +187,11 @@ public class ItemEntity extends Entity implements TraceableEntity { + this.applyEffectsFromBlocks(); + float f = 0.98F; + +- if (this.onGround()) { ++ // Paper start - Friction API ++ if (frictionState == net.kyori.adventure.util.TriState.FALSE) { ++ f = 1F; ++ } else if (this.onGround()) { ++ // Paper end - Friction API + f = this.level().getBlockState(this.getBlockPosBelowThatAffectsMyMovement()).getBlock().getFriction() * 0.98F; + } + +@@ -409,6 +414,11 @@ public class ItemEntity extends Entity implements TraceableEntity { + + @Override + public void addAdditionalSaveData(CompoundTag nbt) { ++ // Paper start - Friction API ++ if (this.frictionState != net.kyori.adventure.util.TriState.NOT_SET) { ++ nbt.putString("Paper.FrictionState", this.frictionState.toString()); ++ } ++ // Paper end - Friction API + nbt.putShort("Health", (short) this.health); + nbt.putShort("Age", (short) this.age); + nbt.putShort("PickupDelay", (short) this.pickupDelay); +@@ -451,6 +461,17 @@ public class ItemEntity extends Entity implements TraceableEntity { + this.setItem(ItemStack.EMPTY); + } + ++ // Paper start - Friction API ++ if (nbt.contains("Paper.FrictionState")) { ++ String fs = nbt.getString("Paper.FrictionState"); ++ try { ++ frictionState = net.kyori.adventure.util.TriState.valueOf(fs); ++ } catch (Exception ignored) { ++ com.mojang.logging.LogUtils.getLogger().error("Unknown friction state " + fs + " for " + this); ++ } ++ } ++ // Paper end - Friction API ++ + if (this.getItem().isEmpty()) { + this.discard(null); // CraftBukkit - add Bukkit remove cause + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +index 1a291dd8a287db30e71dcb315599fc4b038764c4..30d62ee4d5cd2ddacb8783b5bbbf475d592b3e02 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +@@ -99,6 +99,18 @@ public class CraftItem extends CraftEntity implements Item { + this.getHandle().age = willAge ? 0 : NO_AGE_TIME; + } + ++ @org.jetbrains.annotations.NotNull ++ @Override ++ public net.kyori.adventure.util.TriState getFrictionState() { ++ return this.getHandle().frictionState; ++ } ++ ++ @Override ++ public void setFrictionState(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState state) { ++ java.util.Objects.requireNonNull(state, "state may not be null"); ++ this.getHandle().frictionState = state; ++ } ++ + @Override + public int getHealth() { + return this.getHandle().health; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 1ceaa081231a617bd87331b308c24d9c7a8dcf2b..2fd4a3068d86a37cc18c9203448823c53d590ffb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1198,4 +1198,17 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + nmsStack.hurtAndBreak(amount, this.getHandle(), slot, true); + } + // Paper end - ItemStack damage API ++ // Paper start - friction API ++ @org.jetbrains.annotations.NotNull ++ @Override ++ public net.kyori.adventure.util.TriState getFrictionState() { ++ return this.getHandle().frictionState; ++ } ++ ++ @Override ++ public void setFrictionState(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState state) { ++ java.util.Objects.requireNonNull(state, "state may not be null"); ++ this.getHandle().frictionState = state; ++ } ++ // Paper end - friction API + } diff --git a/patches/server/0763-ItemStack-damage-API.patch b/patches/server/0763-ItemStack-damage-API.patch deleted file mode 100644 index 55e7f06af1..0000000000 --- a/patches/server/0763-ItemStack-damage-API.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 8 May 2022 13:35:45 -0700 -Subject: [PATCH] ItemStack damage API - -Adds methods notify clients about item breaks and -to simulate damage done to an itemstack and all -the logic associated with damaging them - -== AT == -public net.minecraft.world.entity.LivingEntity entityEventForEquipmentBreak(Lnet/minecraft/world/entity/EquipmentSlot;)B - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index bcb3a45166e5dd75dd727adf92304b3a75399c8d..90a55f00c36903d52630c51bf69322973a2b5274 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -693,8 +693,13 @@ public final class ItemStack implements DataComponentHolder { - } - - public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent -+ // Paper start - add force boolean overload -+ this.hurtAndBreak(amount, world, player, breakCallback, false); -+ } -+ public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback, boolean force) { // Paper - Add EntityDamageItemEvent -+ // Paper end - int originalDamage = amount; // Paper - Expand PlayerItemDamageEvent -- int j = this.processDurabilityChange(amount, world, player); -+ int j = this.processDurabilityChange(amount, world, player, force); // Paper - // CraftBukkit start - if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent - PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j, originalDamage); // Paper - Add EntityDamageItemEvent -@@ -726,7 +731,12 @@ public final class ItemStack implements DataComponentHolder { - } - - private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable LivingEntity player) { // Paper - Add EntityDamageItemEvent -- return !this.isDamageableItem() ? 0 : (player instanceof ServerPlayer && player.hasInfiniteMaterials() ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage)); // Paper - Add EntityDamageItemEvent -+ // Paper start - itemstack damage api -+ return processDurabilityChange(baseDamage, world, player, false); -+ } -+ private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable LivingEntity player, boolean force) { -+ return !this.isDamageableItem() ? 0 : (player instanceof ServerPlayer && player.hasInfiniteMaterials() && !force ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage)); // Paper - Add EntityDamageItemEvent -+ // Paper end - itemstack damage api - } - - private void applyDamage(int damage, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent -@@ -766,6 +776,11 @@ public final class ItemStack implements DataComponentHolder { - } - - public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot) { -+ // Paper start - add param to skip infinite mats check -+ this.hurtAndBreak(amount, entity, slot, false); -+ } -+ public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot, boolean force) { -+ // Paper end - add param to skip infinite mats check - Level world = entity.level(); - - if (world instanceof ServerLevel worldserver) { -@@ -778,8 +793,8 @@ public final class ItemStack implements DataComponentHolder { - } - - this.hurtAndBreak(amount, worldserver, entity, (item) -> { // Paper - Add EntityDamageItemEvent -- entity.onEquippedItemBroken(item, slot); -- }); -+ if (slot != null) entity.onEquippedItemBroken(item, slot); // Paper - itemstack damage API - do not process entity related callbacks when damaging from API -+ }, force); // Paper - itemstack damage API - } - - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 4fa19ddb1414282020e118eea298d57d2bf42754..1ceaa081231a617bd87331b308c24d9c7a8dcf2b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1154,4 +1154,48 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - this.getHandle().knockback(strength, directionX, directionZ); - }; - // Paper end - knockback API -+ -+ // Paper start - ItemStack damage API -+ public void broadcastSlotBreak(final org.bukkit.inventory.EquipmentSlot slot) { -+ this.getHandle().level().broadcastEntityEvent(this.getHandle(), net.minecraft.world.entity.LivingEntity.entityEventForEquipmentBreak(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot))); -+ } -+ -+ @Override -+ public void broadcastSlotBreak(final org.bukkit.inventory.EquipmentSlot slot, final Collection players) { -+ if (players.isEmpty()) { -+ return; -+ } -+ final net.minecraft.network.protocol.game.ClientboundEntityEventPacket packet = new net.minecraft.network.protocol.game.ClientboundEntityEventPacket( -+ this.getHandle(), -+ net.minecraft.world.entity.LivingEntity.entityEventForEquipmentBreak(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)) -+ ); -+ players.forEach(player -> ((CraftPlayer) player).getHandle().connection.send(packet)); -+ } -+ -+ @Override -+ public ItemStack damageItemStack(ItemStack stack, final int amount) { -+ final net.minecraft.world.item.ItemStack nmsStack; -+ if (stack instanceof final CraftItemStack craftItemStack) { -+ if (craftItemStack.handle == null || craftItemStack.handle.isEmpty()) { -+ return stack; -+ } -+ nmsStack = craftItemStack.handle; -+ } else { -+ nmsStack = CraftItemStack.asNMSCopy(stack); -+ stack = CraftItemStack.asCraftMirror(nmsStack); // mirror to capture changes in hurt logic & events -+ } -+ this.damageItemStack0(nmsStack, amount, null); -+ return stack; -+ } -+ -+ @Override -+ public void damageItemStack(final org.bukkit.inventory.EquipmentSlot slot, final int amount) { -+ final net.minecraft.world.entity.EquipmentSlot nmsSlot = org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot); -+ this.damageItemStack0(this.getHandle().getItemBySlot(nmsSlot), amount, nmsSlot); -+ } -+ -+ private void damageItemStack0(final net.minecraft.world.item.ItemStack nmsStack, final int amount, final net.minecraft.world.entity.EquipmentSlot slot) { -+ nmsStack.hurtAndBreak(amount, this.getHandle(), slot, true); -+ } -+ // Paper end - ItemStack damage API - } diff --git a/patches/server/0764-Ability-to-control-player-s-insomnia-and-phantoms.patch b/patches/server/0764-Ability-to-control-player-s-insomnia-and-phantoms.patch new file mode 100644 index 0000000000..0b482955d5 --- /dev/null +++ b/patches/server/0764-Ability-to-control-player-s-insomnia-and-phantoms.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jan Villim +Date: Sat, 22 Jan 2022 17:56:19 +0100 +Subject: [PATCH] Ability to control player's insomnia and phantoms + + +diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java +index 721321a19ce056f82de2bef44a8791dc9d5b3418..6bf691fcc6486bde73bae30eff09142802c29eda 100644 +--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java ++++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java +@@ -27,7 +27,18 @@ public final class EntitySelector { + }; + public static final Predicate CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith); + public static final Predicate CAN_BE_PICKED = EntitySelector.NO_SPECTATORS.and(Entity::isPickable); +- public static Predicate IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper - Add phantom creative and insomniac controls ++ // Paper start - Ability to control player's insomnia and phantoms ++ public static Predicate IS_INSOMNIAC = (player) -> { ++ net.minecraft.server.level.ServerPlayer serverPlayer = (net.minecraft.server.level.ServerPlayer) player; ++ int playerInsomniaTicks = serverPlayer.level().paperConfig().entities.behavior.playerInsomniaStartTicks; ++ ++ if (playerInsomniaTicks <= 0) { ++ return false; ++ } ++ ++ return net.minecraft.util.Mth.clamp(serverPlayer.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= playerInsomniaTicks; ++ }; ++ // Paper end - Ability to control player's insomnia and phantoms + + private EntitySelector() {} + // Paper start - Affects Spawning API +diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java +index 7d407a7597f3ae576ac7e94bc2eb96d9dcd78dd3..021221da5d0315f6e371380a705ac6b3f6ac18d3 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java +@@ -32,13 +32,22 @@ public class PhantomSpawner implements CustomSpawner { + } else if (!world.getGameRules().getBoolean(GameRules.RULE_DOINSOMNIA)) { + return 0; + } else { ++ // Paper start - Ability to control player's insomnia and phantoms ++ if (world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds <= 0) { ++ return 0; ++ } ++ // Paper end - Ability to control player's insomnia and phantoms + RandomSource randomsource = world.random; + + --this.nextTick; + if (this.nextTick > 0) { + return 0; + } else { +- this.nextTick += (60 + randomsource.nextInt(60)) * 20; ++ // Paper start - Ability to control player's insomnia and phantoms ++ int spawnAttemptMinSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMinSeconds; ++ int spawnAttemptMaxSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; ++ this.nextTick += (spawnAttemptMinSeconds + randomsource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; ++ // Paper end - Ability to control player's insomnia and phantoms + if (world.getSkyDarken() < 5 && world.dimensionType().hasSkyLight()) { + return 0; + } else { +@@ -59,7 +68,7 @@ public class PhantomSpawner implements CustomSpawner { + int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); + boolean flag2 = true; + +- if (randomsource.nextInt(j) >= 72000) { ++ if (randomsource.nextInt(j) >= world.paperConfig().entities.behavior.playerInsomniaStartTicks) { // Paper - Ability to control player's insomnia and phantoms + BlockPos blockposition1 = blockposition.above(20 + randomsource.nextInt(15)).east(-10 + randomsource.nextInt(21)).south(-10 + randomsource.nextInt(21)); + BlockState iblockdata = world.getBlockState(blockposition1); + FluidState fluid = world.getFluidState(blockposition1); diff --git a/patches/server/0764-Friction-API.patch b/patches/server/0764-Friction-API.patch deleted file mode 100644 index 469868818a..0000000000 --- a/patches/server/0764-Friction-API.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Wed, 15 Sep 2021 20:44:22 +0200 -Subject: [PATCH] Friction API - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 2c343617f9467bbef03f4d131ce94b1f1a090a80..5520d0cdd5af75a6188a68f809aafb6c5880878a 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -298,6 +298,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - public boolean bukkitPickUpLoot; - public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper - public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event -+ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API - - @Override - public float getBukkitYaw() { -@@ -724,7 +725,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - public boolean shouldDiscardFriction() { -- return this.discardFriction; -+ return !this.frictionState.toBooleanOrElse(!this.discardFriction); // Paper - Friction API - } - - public void setDiscardFriction(boolean noDrag) { -@@ -798,6 +799,11 @@ public abstract class LivingEntity extends Entity implements Attackable { - - @Override - public void addAdditionalSaveData(CompoundTag nbt) { -+ // Paper start - Friction API -+ if (this.frictionState != net.kyori.adventure.util.TriState.NOT_SET) { -+ nbt.putString("Paper.FrictionState", this.frictionState.toString()); -+ } -+ // Paper end - Friction API - nbt.putFloat("Health", this.getHealth()); - nbt.putShort("HurtTime", (short) this.hurtTime); - nbt.putInt("HurtByTimestamp", this.lastHurtByMobTimestamp); -@@ -841,6 +847,16 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - this.internalSetAbsorptionAmount(absorptionAmount); - // Paper end - Check for NaN -+ // Paper start - Friction API -+ if (nbt.contains("Paper.FrictionState")) { -+ String fs = nbt.getString("Paper.FrictionState"); -+ try { -+ frictionState = net.kyori.adventure.util.TriState.valueOf(fs); -+ } catch (Exception ignored) { -+ LOGGER.error("Unknown friction state " + fs + " for " + this); -+ } -+ } -+ // Paper end - Friction API - if (nbt.contains("attributes", 9) && this.level() != null && !this.level().isClientSide) { - this.getAttributes().load(nbt.getList("attributes", 10)); - } -diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -index aa41c4cf8d3ae291c4147118c96190ff0bb807b2..e83a705f54063a17fc69a22683333aacad5a43ce 100644 ---- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -@@ -63,6 +63,7 @@ public class ItemEntity extends Entity implements TraceableEntity { - private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit - public boolean canMobPickup = true; // Paper - Item#canEntityPickup - private int despawnRate = -1; // Paper - Alternative item-despawn-rate -+ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API - - public ItemEntity(EntityType type, Level world) { - super(type, world); -@@ -186,7 +187,11 @@ public class ItemEntity extends Entity implements TraceableEntity { - this.applyEffectsFromBlocks(); - float f = 0.98F; - -- if (this.onGround()) { -+ // Paper start - Friction API -+ if (frictionState == net.kyori.adventure.util.TriState.FALSE) { -+ f = 1F; -+ } else if (this.onGround()) { -+ // Paper end - Friction API - f = this.level().getBlockState(this.getBlockPosBelowThatAffectsMyMovement()).getBlock().getFriction() * 0.98F; - } - -@@ -409,6 +414,11 @@ public class ItemEntity extends Entity implements TraceableEntity { - - @Override - public void addAdditionalSaveData(CompoundTag nbt) { -+ // Paper start - Friction API -+ if (this.frictionState != net.kyori.adventure.util.TriState.NOT_SET) { -+ nbt.putString("Paper.FrictionState", this.frictionState.toString()); -+ } -+ // Paper end - Friction API - nbt.putShort("Health", (short) this.health); - nbt.putShort("Age", (short) this.age); - nbt.putShort("PickupDelay", (short) this.pickupDelay); -@@ -451,6 +461,17 @@ public class ItemEntity extends Entity implements TraceableEntity { - this.setItem(ItemStack.EMPTY); - } - -+ // Paper start - Friction API -+ if (nbt.contains("Paper.FrictionState")) { -+ String fs = nbt.getString("Paper.FrictionState"); -+ try { -+ frictionState = net.kyori.adventure.util.TriState.valueOf(fs); -+ } catch (Exception ignored) { -+ com.mojang.logging.LogUtils.getLogger().error("Unknown friction state " + fs + " for " + this); -+ } -+ } -+ // Paper end - Friction API -+ - if (this.getItem().isEmpty()) { - this.discard(null); // CraftBukkit - add Bukkit remove cause - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -index 1a291dd8a287db30e71dcb315599fc4b038764c4..30d62ee4d5cd2ddacb8783b5bbbf475d592b3e02 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -@@ -99,6 +99,18 @@ public class CraftItem extends CraftEntity implements Item { - this.getHandle().age = willAge ? 0 : NO_AGE_TIME; - } - -+ @org.jetbrains.annotations.NotNull -+ @Override -+ public net.kyori.adventure.util.TriState getFrictionState() { -+ return this.getHandle().frictionState; -+ } -+ -+ @Override -+ public void setFrictionState(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState state) { -+ java.util.Objects.requireNonNull(state, "state may not be null"); -+ this.getHandle().frictionState = state; -+ } -+ - @Override - public int getHealth() { - return this.getHandle().health; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 1ceaa081231a617bd87331b308c24d9c7a8dcf2b..2fd4a3068d86a37cc18c9203448823c53d590ffb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1198,4 +1198,17 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - nmsStack.hurtAndBreak(amount, this.getHandle(), slot, true); - } - // Paper end - ItemStack damage API -+ // Paper start - friction API -+ @org.jetbrains.annotations.NotNull -+ @Override -+ public net.kyori.adventure.util.TriState getFrictionState() { -+ return this.getHandle().frictionState; -+ } -+ -+ @Override -+ public void setFrictionState(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState state) { -+ java.util.Objects.requireNonNull(state, "state may not be null"); -+ this.getHandle().frictionState = state; -+ } -+ // Paper end - friction API - } diff --git a/patches/server/0765-Ability-to-control-player-s-insomnia-and-phantoms.patch b/patches/server/0765-Ability-to-control-player-s-insomnia-and-phantoms.patch deleted file mode 100644 index 0b482955d5..0000000000 --- a/patches/server/0765-Ability-to-control-player-s-insomnia-and-phantoms.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jan Villim -Date: Sat, 22 Jan 2022 17:56:19 +0100 -Subject: [PATCH] Ability to control player's insomnia and phantoms - - -diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java -index 721321a19ce056f82de2bef44a8791dc9d5b3418..6bf691fcc6486bde73bae30eff09142802c29eda 100644 ---- a/src/main/java/net/minecraft/world/entity/EntitySelector.java -+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java -@@ -27,7 +27,18 @@ public final class EntitySelector { - }; - public static final Predicate CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith); - public static final Predicate CAN_BE_PICKED = EntitySelector.NO_SPECTATORS.and(Entity::isPickable); -- public static Predicate IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper - Add phantom creative and insomniac controls -+ // Paper start - Ability to control player's insomnia and phantoms -+ public static Predicate IS_INSOMNIAC = (player) -> { -+ net.minecraft.server.level.ServerPlayer serverPlayer = (net.minecraft.server.level.ServerPlayer) player; -+ int playerInsomniaTicks = serverPlayer.level().paperConfig().entities.behavior.playerInsomniaStartTicks; -+ -+ if (playerInsomniaTicks <= 0) { -+ return false; -+ } -+ -+ return net.minecraft.util.Mth.clamp(serverPlayer.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= playerInsomniaTicks; -+ }; -+ // Paper end - Ability to control player's insomnia and phantoms - - private EntitySelector() {} - // Paper start - Affects Spawning API -diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -index 7d407a7597f3ae576ac7e94bc2eb96d9dcd78dd3..021221da5d0315f6e371380a705ac6b3f6ac18d3 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -@@ -32,13 +32,22 @@ public class PhantomSpawner implements CustomSpawner { - } else if (!world.getGameRules().getBoolean(GameRules.RULE_DOINSOMNIA)) { - return 0; - } else { -+ // Paper start - Ability to control player's insomnia and phantoms -+ if (world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds <= 0) { -+ return 0; -+ } -+ // Paper end - Ability to control player's insomnia and phantoms - RandomSource randomsource = world.random; - - --this.nextTick; - if (this.nextTick > 0) { - return 0; - } else { -- this.nextTick += (60 + randomsource.nextInt(60)) * 20; -+ // Paper start - Ability to control player's insomnia and phantoms -+ int spawnAttemptMinSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMinSeconds; -+ int spawnAttemptMaxSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; -+ this.nextTick += (spawnAttemptMinSeconds + randomsource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; -+ // Paper end - Ability to control player's insomnia and phantoms - if (world.getSkyDarken() < 5 && world.dimensionType().hasSkyLight()) { - return 0; - } else { -@@ -59,7 +68,7 @@ public class PhantomSpawner implements CustomSpawner { - int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); - boolean flag2 = true; - -- if (randomsource.nextInt(j) >= 72000) { -+ if (randomsource.nextInt(j) >= world.paperConfig().entities.behavior.playerInsomniaStartTicks) { // Paper - Ability to control player's insomnia and phantoms - BlockPos blockposition1 = blockposition.above(20 + randomsource.nextInt(15)).east(-10 + randomsource.nextInt(21)).south(-10 + randomsource.nextInt(21)); - BlockState iblockdata = world.getBlockState(blockposition1); - FluidState fluid = world.getFluidState(blockposition1); diff --git a/patches/server/0765-Fix-premature-player-kicks-on-shutdown.patch b/patches/server/0765-Fix-premature-player-kicks-on-shutdown.patch new file mode 100644 index 0000000000..5a0d9d65c0 --- /dev/null +++ b/patches/server/0765-Fix-premature-player-kicks-on-shutdown.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Thu, 11 Apr 2024 16:37:44 +0100 +Subject: [PATCH] Fix premature player kicks on shutdown + +When the server is stopping, the default execution handler method will throw a +RejectedExecutionException in order to prevent further execution, this causes +us to lose the actual kick reason. To mitigate this, we'll use a seperate marked +class in order to gracefully ignore these. + +diff --git a/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java b/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2c5cd77103c5a33d4349ab6b9ee2d8378bb60eb4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.util; ++ ++import java.util.concurrent.RejectedExecutionException; ++ ++public class ServerStopRejectedExecutionException extends RejectedExecutionException { ++ public ServerStopRejectedExecutionException() { ++ } ++ ++ public ServerStopRejectedExecutionException(final String message) { ++ super(message); ++ } ++ ++ public ServerStopRejectedExecutionException(final String message, final Throwable cause) { ++ super(message, cause); ++ } ++ ++ public ServerStopRejectedExecutionException(final Throwable cause) { ++ super(cause); ++ } ++} +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index 4d9f1fc884050993287adfa4578a87da710623fb..a8dfe7a4b3d01bf75587be078f471d1ef1d7a667 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -285,6 +285,7 @@ public class Connection extends SimpleChannelInboundHandler> { + Connection.genericsFtw(packet, packetlistener); + } catch (RunningOnDifferentThreadException cancelledpackethandleexception) { + ; ++ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop + } catch (RejectedExecutionException rejectedexecutionexception) { + this.disconnect((Component) Component.translatable("multiplayer.disconnect.server_shutdown")); + } catch (ClassCastException classcastexception) { +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index cb40a2d855e7ac8c1c8b4ec679fd057a31f3fc6f..8f7a808b0c89953a7f2932e68e2c85f9330469f2 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2127,7 +2127,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Thu, 11 Apr 2024 16:37:44 +0100 -Subject: [PATCH] Fix premature player kicks on shutdown - -When the server is stopping, the default execution handler method will throw a -RejectedExecutionException in order to prevent further execution, this causes -us to lose the actual kick reason. To mitigate this, we'll use a seperate marked -class in order to gracefully ignore these. - -diff --git a/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java b/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2c5cd77103c5a33d4349ab6b9ee2d8378bb60eb4 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java -@@ -0,0 +1,20 @@ -+package io.papermc.paper.util; -+ -+import java.util.concurrent.RejectedExecutionException; -+ -+public class ServerStopRejectedExecutionException extends RejectedExecutionException { -+ public ServerStopRejectedExecutionException() { -+ } -+ -+ public ServerStopRejectedExecutionException(final String message) { -+ super(message); -+ } -+ -+ public ServerStopRejectedExecutionException(final String message, final Throwable cause) { -+ super(message, cause); -+ } -+ -+ public ServerStopRejectedExecutionException(final Throwable cause) { -+ super(cause); -+ } -+} -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 4d9f1fc884050993287adfa4578a87da710623fb..a8dfe7a4b3d01bf75587be078f471d1ef1d7a667 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -285,6 +285,7 @@ public class Connection extends SimpleChannelInboundHandler> { - Connection.genericsFtw(packet, packetlistener); - } catch (RunningOnDifferentThreadException cancelledpackethandleexception) { - ; -+ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop - } catch (RejectedExecutionException rejectedexecutionexception) { - this.disconnect((Component) Component.translatable("multiplayer.disconnect.server_shutdown")); - } catch (ClassCastException classcastexception) { -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 57080f1343aa5408d70b320375813b00b205aafa..736ff3988d66b8694475d5f62673da61fcb76179 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2171,7 +2171,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Fri, 14 Jan 2022 10:20:40 -0800 +Subject: [PATCH] Sync offhand slot in menus + +Menus don't add slots for the offhand, so on sendAllDataToRemote calls the +offhand slot isn't sent. This is not correct because you *can* put stuff into the offhand +by pressing the offhand swap item + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 04e3c75c9abfaccb6d2d59d234e5169258b77553..25b1e8bec23465f0e9a17f156bdff7fe716db84c 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -350,6 +350,13 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + } + ++ // Paper start - Sync offhand slot in menus ++ @Override ++ public void sendOffHandSlotChange() { ++ ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(ServerPlayer.this.inventoryMenu.containerId, ServerPlayer.this.inventoryMenu.incrementStateId(), net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy())); ++ } ++ // Paper end - Sync offhand slot in menus ++ + @Override + public void sendSlotChange(AbstractContainerMenu handler, int slot, ItemStack stack) { + ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(handler.containerId, handler.incrementStateId(), slot, stack)); +diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +index d830504d08c9de92797c432a868c1ee9dfc46a91..fc23e2dc42e907d5f8dc134a06102cc3e7fde515 100644 +--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -228,6 +228,7 @@ public abstract class AbstractContainerMenu { + + if (this.synchronizer != null) { + this.synchronizer.sendInitialData(this, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray()); ++ this.synchronizer.sendOffHandSlotChange(); // Paper - Sync offhand slot in menus; update player's offhand since the offhand slot is not added to the slots for menus but can be changed by swapping from a menu slot + } + + } +diff --git a/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java b/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java +index ff4fa86f9408e83e505f7e27692d3423f8570c48..a45ef5fcffc05e4e30801b73e82d29c6dbf5b8fd 100644 +--- a/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java ++++ b/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java +@@ -6,6 +6,7 @@ import net.minecraft.world.item.ItemStack; + public interface ContainerSynchronizer { + void sendInitialData(AbstractContainerMenu handler, NonNullList stacks, ItemStack cursorStack, int[] properties); + ++ default void sendOffHandSlotChange() {} // Paper - Sync offhand slot in menus + void sendSlotChange(AbstractContainerMenu handler, int slot, ItemStack stack); + + void sendCarriedChange(AbstractContainerMenu handler, ItemStack stack); diff --git a/patches/server/0767-Player-Entity-Tracking-Events.patch b/patches/server/0767-Player-Entity-Tracking-Events.patch new file mode 100644 index 0000000000..8010e7f0d6 --- /dev/null +++ b/patches/server/0767-Player-Entity-Tracking-Events.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yannick Lamprecht +Date: Wed, 30 Mar 2022 18:16:52 +0200 +Subject: [PATCH] Player Entity Tracking Events + + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index e1c69c3c8e4809c7ccd2e1e12ee8538ab4bd3d5c..53e180e230d5a1652f3e19193243c37095d6b39e 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1586,7 +1586,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // CraftBukkit end + if (flag) { + if (this.seenBy.add(player.connection)) { ++ // Paper start - entity tracking events ++ if (io.papermc.paper.event.player.PlayerTrackEntityEvent.getHandlerList().getRegisteredListeners().length == 0 || new io.papermc.paper.event.player.PlayerTrackEntityEvent(player.getBukkitEntity(), this.entity.getBukkitEntity()).callEvent()) { + this.serverEntity.addPairing(player); ++ } ++ // Paper end - entity tracking events + } + } else if (this.seenBy.remove(player.connection)) { + this.serverEntity.removePairing(player); +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 8aabd17178543eab0724a05226e4741ead85ea87..47a2cd3ea7c88681929351c6db9090149e2c4f2e 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -4069,7 +4069,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + public void startSeenByPlayer(ServerPlayer player) {} + +- public void stopSeenByPlayer(ServerPlayer player) {} ++ // Paper start - entity tracking events ++ public void stopSeenByPlayer(ServerPlayer player) { ++ // Since this event cannot be cancelled, we should call it here to catch all "un-tracks" ++ if (io.papermc.paper.event.player.PlayerUntrackEntityEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ new io.papermc.paper.event.player.PlayerUntrackEntityEvent(player.getBukkitEntity(), this.getBukkitEntity()).callEvent(); ++ } ++ } ++ // Paper end - entity tracking events + + public float rotate(Rotation rotation) { + float f = Mth.wrapDegrees(this.getYRot()); diff --git a/patches/server/0767-Sync-offhand-slot-in-menus.patch b/patches/server/0767-Sync-offhand-slot-in-menus.patch deleted file mode 100644 index b8a6ce0108..0000000000 --- a/patches/server/0767-Sync-offhand-slot-in-menus.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 14 Jan 2022 10:20:40 -0800 -Subject: [PATCH] Sync offhand slot in menus - -Menus don't add slots for the offhand, so on sendAllDataToRemote calls the -offhand slot isn't sent. This is not correct because you *can* put stuff into the offhand -by pressing the offhand swap item - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 04e3c75c9abfaccb6d2d59d234e5169258b77553..25b1e8bec23465f0e9a17f156bdff7fe716db84c 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -350,6 +350,13 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - } - -+ // Paper start - Sync offhand slot in menus -+ @Override -+ public void sendOffHandSlotChange() { -+ ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(ServerPlayer.this.inventoryMenu.containerId, ServerPlayer.this.inventoryMenu.incrementStateId(), net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy())); -+ } -+ // Paper end - Sync offhand slot in menus -+ - @Override - public void sendSlotChange(AbstractContainerMenu handler, int slot, ItemStack stack) { - ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(handler.containerId, handler.incrementStateId(), slot, stack)); -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index d830504d08c9de92797c432a868c1ee9dfc46a91..fc23e2dc42e907d5f8dc134a06102cc3e7fde515 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -228,6 +228,7 @@ public abstract class AbstractContainerMenu { - - if (this.synchronizer != null) { - this.synchronizer.sendInitialData(this, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray()); -+ this.synchronizer.sendOffHandSlotChange(); // Paper - Sync offhand slot in menus; update player's offhand since the offhand slot is not added to the slots for menus but can be changed by swapping from a menu slot - } - - } -diff --git a/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java b/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java -index ff4fa86f9408e83e505f7e27692d3423f8570c48..a45ef5fcffc05e4e30801b73e82d29c6dbf5b8fd 100644 ---- a/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java -+++ b/src/main/java/net/minecraft/world/inventory/ContainerSynchronizer.java -@@ -6,6 +6,7 @@ import net.minecraft.world.item.ItemStack; - public interface ContainerSynchronizer { - void sendInitialData(AbstractContainerMenu handler, NonNullList stacks, ItemStack cursorStack, int[] properties); - -+ default void sendOffHandSlotChange() {} // Paper - Sync offhand slot in menus - void sendSlotChange(AbstractContainerMenu handler, int slot, ItemStack stack); - - void sendCarriedChange(AbstractContainerMenu handler, ItemStack stack); diff --git a/patches/server/0768-Limit-pet-look-distance.patch b/patches/server/0768-Limit-pet-look-distance.patch new file mode 100644 index 0000000000..983f861539 --- /dev/null +++ b/patches/server/0768-Limit-pet-look-distance.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Tue, 6 Dec 2022 18:45:54 +0100 +Subject: [PATCH] Limit pet look distance + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java +index bf9ad63343fa07105f217625bb81ed637a7f7f7e..15d7be9ed4a973044dd4399db46aaa244730b836 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java +@@ -72,7 +72,7 @@ public class FollowOwnerGoal extends Goal { + public void tick() { + boolean bl = this.tamable.shouldTryTeleportToOwner(); + if (!bl) { +- this.tamable.getLookControl().setLookAt(this.owner, 10.0F, (float)this.tamable.getMaxHeadXRot()); ++ if (this.tamable.distanceToSqr(this.owner) <= 16 * 16) this.tamable.getLookControl().setLookAt(this.owner, 10.0F, (float)this.tamable.getMaxHeadXRot()); // Paper - Limit pet look distance + } + + if (--this.timeToRecalcPath <= 0) { diff --git a/patches/server/0768-Player-Entity-Tracking-Events.patch b/patches/server/0768-Player-Entity-Tracking-Events.patch deleted file mode 100644 index e3837eb40f..0000000000 --- a/patches/server/0768-Player-Entity-Tracking-Events.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Yannick Lamprecht -Date: Wed, 30 Mar 2022 18:16:52 +0200 -Subject: [PATCH] Player Entity Tracking Events - - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 3f3124bbb5077a18c3d3afac7748a47e84b8fe35..7810df9c5045a78c2731ee416366da4f973e5d29 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1592,7 +1592,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // CraftBukkit end - if (flag) { - if (this.seenBy.add(player.connection)) { -+ // Paper start - entity tracking events -+ if (io.papermc.paper.event.player.PlayerTrackEntityEvent.getHandlerList().getRegisteredListeners().length == 0 || new io.papermc.paper.event.player.PlayerTrackEntityEvent(player.getBukkitEntity(), this.entity.getBukkitEntity()).callEvent()) { - this.serverEntity.addPairing(player); -+ } -+ // Paper end - entity tracking events - } - } else if (this.seenBy.remove(player.connection)) { - this.serverEntity.removePairing(player); -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 8aabd17178543eab0724a05226e4741ead85ea87..47a2cd3ea7c88681929351c6db9090149e2c4f2e 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4069,7 +4069,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - public void startSeenByPlayer(ServerPlayer player) {} - -- public void stopSeenByPlayer(ServerPlayer player) {} -+ // Paper start - entity tracking events -+ public void stopSeenByPlayer(ServerPlayer player) { -+ // Since this event cannot be cancelled, we should call it here to catch all "un-tracks" -+ if (io.papermc.paper.event.player.PlayerUntrackEntityEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ new io.papermc.paper.event.player.PlayerUntrackEntityEvent(player.getBukkitEntity(), this.getBukkitEntity()).callEvent(); -+ } -+ } -+ // Paper end - entity tracking events - - public float rotate(Rotation rotation) { - float f = Mth.wrapDegrees(this.getYRot()); diff --git a/patches/server/0769-Limit-pet-look-distance.patch b/patches/server/0769-Limit-pet-look-distance.patch deleted file mode 100644 index 983f861539..0000000000 --- a/patches/server/0769-Limit-pet-look-distance.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Tue, 6 Dec 2022 18:45:54 +0100 -Subject: [PATCH] Limit pet look distance - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java -index bf9ad63343fa07105f217625bb81ed637a7f7f7e..15d7be9ed4a973044dd4399db46aaa244730b836 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java -@@ -72,7 +72,7 @@ public class FollowOwnerGoal extends Goal { - public void tick() { - boolean bl = this.tamable.shouldTryTeleportToOwner(); - if (!bl) { -- this.tamable.getLookControl().setLookAt(this.owner, 10.0F, (float)this.tamable.getMaxHeadXRot()); -+ if (this.tamable.distanceToSqr(this.owner) <= 16 * 16) this.tamable.getLookControl().setLookAt(this.owner, 10.0F, (float)this.tamable.getMaxHeadXRot()); // Paper - Limit pet look distance - } - - if (--this.timeToRecalcPath <= 0) { diff --git a/patches/server/0769-fix-Instruments.patch b/patches/server/0769-fix-Instruments.patch new file mode 100644 index 0000000000..ff46175c0f --- /dev/null +++ b/patches/server/0769-fix-Instruments.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 9 Dec 2022 01:47:23 -0800 +Subject: [PATCH] fix Instruments + +properly handle Player#playNote + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 7ef67f0b5da392fa09a99d1213eefa373aad96b6..f710776d2a81c426cbe75532b06da4f8b1ef4787 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -785,7 +785,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + Sound instrumentSound = instrument.getSound(); + if (instrumentSound == null) return; + +- float pitch = note.getPitch(); ++ // Paper start - use correct pitch (modeled off of NoteBlock) ++ final net.minecraft.world.level.block.state.properties.NoteBlockInstrument noteBlockInstrument = CraftBlockData.toNMS(instrument, net.minecraft.world.level.block.state.properties.NoteBlockInstrument.class); ++ final float pitch = noteBlockInstrument.isTunable() ? note.getPitch() : 1.0f; ++ // Paper end + this.getHandle().connection.send(new ClientboundSoundPacket(CraftSound.bukkitToMinecraftHolder(instrumentSound), net.minecraft.sounds.SoundSource.RECORDS, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), 3.0f, pitch, this.getHandle().getRandom().nextLong())); + } + +diff --git a/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java b/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cd718ed01ba5d448cdf0a2b6a39dc7ef2337f70d +--- /dev/null ++++ b/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.block; ++ ++import java.util.Arrays; ++import java.util.stream.Stream; ++import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; ++import org.bukkit.Instrument; ++import org.bukkit.craftbukkit.CraftSound; ++import org.bukkit.craftbukkit.block.data.CraftBlockData; ++import org.bukkit.support.environment.AllFeatures; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++ ++@AllFeatures ++class InstrumentSoundTest { ++ ++ static Stream bukkitInstruments() { ++ return Arrays.stream(Instrument.values()).filter(i -> i.getSound() != null); ++ } ++ ++ @ParameterizedTest ++ @MethodSource("bukkitInstruments") ++ void checkInstrumentSound(final Instrument bukkit) { ++ final NoteBlockInstrument nms = CraftBlockData.toNMS(bukkit, NoteBlockInstrument.class); ++ assertEquals(nms.getSoundEvent(), CraftSound.bukkitToMinecraftHolder(bukkit.getSound())); ++ } ++} diff --git a/patches/server/0770-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch b/patches/server/0770-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch new file mode 100644 index 0000000000..6825374465 --- /dev/null +++ b/patches/server/0770-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 6 Jul 2020 20:46:50 -0700 +Subject: [PATCH] Improve inlining for some hot BlockBehavior and FluidState + methods + + +diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +index 83a3c877f2969549ea154ad86687e96fdf34d881..0665ca48fe2f8ab1ce1c0306b11be19b06445f74 100644 +--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java ++++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +@@ -969,15 +969,15 @@ public abstract class BlockBehaviour implements FeatureElement { + return this.shapeExceedsCube; // Paper - moved into shape cache init + } + +- public boolean useShapeForLightOcclusion() { ++ public final boolean useShapeForLightOcclusion() { // Paper - Perf: Final for inlining + return this.useShapeForLightOcclusion; + } + +- public int getLightEmission() { ++ public final int getLightEmission() { // Paper - Perf: Final for inlining + return this.lightEmission; + } + +- public boolean isAir() { ++ public final boolean isAir() { // Paper - Perf: Final for inlining + return this.isAir; + } + +@@ -1055,7 +1055,7 @@ public abstract class BlockBehaviour implements FeatureElement { + return this.solidRender; + } + +- public boolean canOcclude() { ++ public final boolean canOcclude() { // Paper - Perf: Final for inlining + return this.canOcclude; + } + +@@ -1276,11 +1276,11 @@ public abstract class BlockBehaviour implements FeatureElement { + return this.getBlock().builtInRegistryHolder().is(key); + } + +- public FluidState getFluidState() { ++ public final FluidState getFluidState() { // Paper - Perf: Final for inlining + return this.fluidState; + } + +- public boolean isRandomlyTicking() { ++ public final boolean isRandomlyTicking() { // Paper - Perf: Final for inlining + return this.isRandomlyTicking; + } + +diff --git a/src/main/java/net/minecraft/world/level/material/FluidState.java b/src/main/java/net/minecraft/world/level/material/FluidState.java +index 8310cb22e2e75d8b2cca32bfe076fdafabb1b0ec..87adfe152abd1b8b4d547034576883c5d1cdf134 100644 +--- a/src/main/java/net/minecraft/world/level/material/FluidState.java ++++ b/src/main/java/net/minecraft/world/level/material/FluidState.java +@@ -26,9 +26,11 @@ public final class FluidState extends StateHolder { + public static final Codec CODEC = codec(BuiltInRegistries.FLUID.byNameCodec(), Fluid::defaultFluidState).stable(); + public static final int AMOUNT_MAX = 9; + public static final int AMOUNT_FULL = 8; ++ protected final boolean isEmpty; // Paper - Perf: moved from isEmpty() + + public FluidState(Fluid fluid, Reference2ObjectArrayMap, Comparable> propertyMap, MapCodec codec) { + super(fluid, propertyMap, codec); ++ this.isEmpty = fluid.isEmpty(); // Paper - Perf: moved from isEmpty() + } + + public Fluid getType() { +@@ -44,7 +46,7 @@ public final class FluidState extends StateHolder { + } + + public boolean isEmpty() { +- return this.getType().isEmpty(); ++ return this.isEmpty; // Paper - Perf: moved into constructor + } + + public float getHeight(BlockGetter world, BlockPos pos) { diff --git a/patches/server/0770-fix-Instruments.patch b/patches/server/0770-fix-Instruments.patch deleted file mode 100644 index ff46175c0f..0000000000 --- a/patches/server/0770-fix-Instruments.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 9 Dec 2022 01:47:23 -0800 -Subject: [PATCH] fix Instruments - -properly handle Player#playNote - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 7ef67f0b5da392fa09a99d1213eefa373aad96b6..f710776d2a81c426cbe75532b06da4f8b1ef4787 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -785,7 +785,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - Sound instrumentSound = instrument.getSound(); - if (instrumentSound == null) return; - -- float pitch = note.getPitch(); -+ // Paper start - use correct pitch (modeled off of NoteBlock) -+ final net.minecraft.world.level.block.state.properties.NoteBlockInstrument noteBlockInstrument = CraftBlockData.toNMS(instrument, net.minecraft.world.level.block.state.properties.NoteBlockInstrument.class); -+ final float pitch = noteBlockInstrument.isTunable() ? note.getPitch() : 1.0f; -+ // Paper end - this.getHandle().connection.send(new ClientboundSoundPacket(CraftSound.bukkitToMinecraftHolder(instrumentSound), net.minecraft.sounds.SoundSource.RECORDS, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), 3.0f, pitch, this.getHandle().getRandom().nextLong())); - } - -diff --git a/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java b/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cd718ed01ba5d448cdf0a2b6a39dc7ef2337f70d ---- /dev/null -+++ b/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java -@@ -0,0 +1,28 @@ -+package io.papermc.paper.block; -+ -+import java.util.Arrays; -+import java.util.stream.Stream; -+import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; -+import org.bukkit.Instrument; -+import org.bukkit.craftbukkit.CraftSound; -+import org.bukkit.craftbukkit.block.data.CraftBlockData; -+import org.bukkit.support.environment.AllFeatures; -+import org.junit.jupiter.params.ParameterizedTest; -+import org.junit.jupiter.params.provider.MethodSource; -+ -+import static org.junit.jupiter.api.Assertions.assertEquals; -+ -+@AllFeatures -+class InstrumentSoundTest { -+ -+ static Stream bukkitInstruments() { -+ return Arrays.stream(Instrument.values()).filter(i -> i.getSound() != null); -+ } -+ -+ @ParameterizedTest -+ @MethodSource("bukkitInstruments") -+ void checkInstrumentSound(final Instrument bukkit) { -+ final NoteBlockInstrument nms = CraftBlockData.toNMS(bukkit, NoteBlockInstrument.class); -+ assertEquals(nms.getSoundEvent(), CraftSound.bukkitToMinecraftHolder(bukkit.getSound())); -+ } -+} diff --git a/patches/server/0771-Add-BlockLockCheckEvent.patch b/patches/server/0771-Add-BlockLockCheckEvent.patch new file mode 100644 index 0000000000..b06f734eb2 --- /dev/null +++ b/patches/server/0771-Add-BlockLockCheckEvent.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 21 May 2022 20:59:45 -0700 +Subject: [PATCH] Add BlockLockCheckEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java +index 4f397dd8e5d333cb2561d03d20511a9194314d1c..1f29b2419914ca9257db6553f01b7e7ec49bfc18 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java +@@ -73,17 +73,44 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co + protected abstract Component getDefaultName(); + + public boolean canOpen(Player player) { +- return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName()); ++ return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName(), this); // Paper - Add BlockLockCheckEvent + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add BlockLockCheckEvent + public static boolean canUnlock(Player player, LockCode lock, Component containerName) { ++ // Paper start - Add BlockLockCheckEvent ++ return canUnlock(player, lock, containerName, null); ++ } ++ public static boolean canUnlock(Player player, LockCode lock, Component containerName, @Nullable BlockEntity blockEntity) { ++ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != null && blockEntity.getLevel().getBlockEntity(blockEntity.getBlockPos()) == blockEntity) { ++ final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(blockEntity.getLevel(), blockEntity.getBlockPos()); ++ net.kyori.adventure.text.Component lockedMessage = net.kyori.adventure.text.Component.translatable("container.isLocked", io.papermc.paper.adventure.PaperAdventure.asAdventure(containerName)); ++ net.kyori.adventure.sound.Sound lockedSound = net.kyori.adventure.sound.Sound.sound(org.bukkit.Sound.BLOCK_CHEST_LOCKED, net.kyori.adventure.sound.Sound.Source.BLOCK, 1.0F, 1.0F); ++ final io.papermc.paper.event.block.BlockLockCheckEvent event = new io.papermc.paper.event.block.BlockLockCheckEvent(block, serverPlayer.getBukkitEntity(), lockedMessage, lockedSound); ++ event.callEvent(); ++ if (event.getResult() == org.bukkit.event.Event.Result.ALLOW) { ++ return true; ++ } else if (event.getResult() == org.bukkit.event.Event.Result.DENY || (!player.isSpectator() && !lock.unlocksWith(event.isUsingCustomKeyItemStack() ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getKeyItem()) : player.getMainHandItem()))) { ++ if (event.getLockedMessage() != null) { ++ event.getPlayer().sendActionBar(event.getLockedMessage()); ++ } ++ if (event.getLockedSound() != null) { ++ event.getPlayer().playSound(event.getLockedSound()); ++ } ++ return false; ++ } else { ++ return true; ++ } ++ } else { // logic below is replaced by logic above ++ // Paper end - Add BlockLockCheckEvent + if (!player.isSpectator() && !lock.unlocksWith(player.getMainHandItem())) { +- player.displayClientMessage(Component.translatable("container.isLocked", containerName), true); ++ player.displayClientMessage(Component.translatable("container.isLocked", containerName), true); // Paper - diff on change + player.playNotifySound(SoundEvents.CHEST_LOCKED, SoundSource.BLOCKS, 1.0F, 1.0F); + return false; + } else { + return true; + } ++ } // Paper - Add BlockLockCheckEvent + } + + protected abstract NonNullList getItems(); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +index edd6017937a7f20a1b43fa15204ec130b524b52b..2a7d896dd9a02acf6e3596e2e2e7ed50f4b88377 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +@@ -472,7 +472,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + @Nullable + @Override + public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory, Player player) { +- return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName()) ? new BeaconMenu(syncId, playerInventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())) : null; ++ return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName(), this) ? new BeaconMenu(syncId, playerInventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())) : null; // Paper - Add BlockLockCheckEvent + } + + @Override diff --git a/patches/server/0771-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch b/patches/server/0771-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch deleted file mode 100644 index 6825374465..0000000000 --- a/patches/server/0771-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 6 Jul 2020 20:46:50 -0700 -Subject: [PATCH] Improve inlining for some hot BlockBehavior and FluidState - methods - - -diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 83a3c877f2969549ea154ad86687e96fdf34d881..0665ca48fe2f8ab1ce1c0306b11be19b06445f74 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -969,15 +969,15 @@ public abstract class BlockBehaviour implements FeatureElement { - return this.shapeExceedsCube; // Paper - moved into shape cache init - } - -- public boolean useShapeForLightOcclusion() { -+ public final boolean useShapeForLightOcclusion() { // Paper - Perf: Final for inlining - return this.useShapeForLightOcclusion; - } - -- public int getLightEmission() { -+ public final int getLightEmission() { // Paper - Perf: Final for inlining - return this.lightEmission; - } - -- public boolean isAir() { -+ public final boolean isAir() { // Paper - Perf: Final for inlining - return this.isAir; - } - -@@ -1055,7 +1055,7 @@ public abstract class BlockBehaviour implements FeatureElement { - return this.solidRender; - } - -- public boolean canOcclude() { -+ public final boolean canOcclude() { // Paper - Perf: Final for inlining - return this.canOcclude; - } - -@@ -1276,11 +1276,11 @@ public abstract class BlockBehaviour implements FeatureElement { - return this.getBlock().builtInRegistryHolder().is(key); - } - -- public FluidState getFluidState() { -+ public final FluidState getFluidState() { // Paper - Perf: Final for inlining - return this.fluidState; - } - -- public boolean isRandomlyTicking() { -+ public final boolean isRandomlyTicking() { // Paper - Perf: Final for inlining - return this.isRandomlyTicking; - } - -diff --git a/src/main/java/net/minecraft/world/level/material/FluidState.java b/src/main/java/net/minecraft/world/level/material/FluidState.java -index 8310cb22e2e75d8b2cca32bfe076fdafabb1b0ec..87adfe152abd1b8b4d547034576883c5d1cdf134 100644 ---- a/src/main/java/net/minecraft/world/level/material/FluidState.java -+++ b/src/main/java/net/minecraft/world/level/material/FluidState.java -@@ -26,9 +26,11 @@ public final class FluidState extends StateHolder { - public static final Codec CODEC = codec(BuiltInRegistries.FLUID.byNameCodec(), Fluid::defaultFluidState).stable(); - public static final int AMOUNT_MAX = 9; - public static final int AMOUNT_FULL = 8; -+ protected final boolean isEmpty; // Paper - Perf: moved from isEmpty() - - public FluidState(Fluid fluid, Reference2ObjectArrayMap, Comparable> propertyMap, MapCodec codec) { - super(fluid, propertyMap, codec); -+ this.isEmpty = fluid.isEmpty(); // Paper - Perf: moved from isEmpty() - } - - public Fluid getType() { -@@ -44,7 +46,7 @@ public final class FluidState extends StateHolder { - } - - public boolean isEmpty() { -- return this.getType().isEmpty(); -+ return this.isEmpty; // Paper - Perf: moved into constructor - } - - public float getHeight(BlockGetter world, BlockPos pos) { diff --git a/patches/server/0772-Add-BlockLockCheckEvent.patch b/patches/server/0772-Add-BlockLockCheckEvent.patch deleted file mode 100644 index b06f734eb2..0000000000 --- a/patches/server/0772-Add-BlockLockCheckEvent.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 21 May 2022 20:59:45 -0700 -Subject: [PATCH] Add BlockLockCheckEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java -index 4f397dd8e5d333cb2561d03d20511a9194314d1c..1f29b2419914ca9257db6553f01b7e7ec49bfc18 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java -@@ -73,17 +73,44 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co - protected abstract Component getDefaultName(); - - public boolean canOpen(Player player) { -- return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName()); -+ return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName(), this); // Paper - Add BlockLockCheckEvent - } - -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add BlockLockCheckEvent - public static boolean canUnlock(Player player, LockCode lock, Component containerName) { -+ // Paper start - Add BlockLockCheckEvent -+ return canUnlock(player, lock, containerName, null); -+ } -+ public static boolean canUnlock(Player player, LockCode lock, Component containerName, @Nullable BlockEntity blockEntity) { -+ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != null && blockEntity.getLevel().getBlockEntity(blockEntity.getBlockPos()) == blockEntity) { -+ final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(blockEntity.getLevel(), blockEntity.getBlockPos()); -+ net.kyori.adventure.text.Component lockedMessage = net.kyori.adventure.text.Component.translatable("container.isLocked", io.papermc.paper.adventure.PaperAdventure.asAdventure(containerName)); -+ net.kyori.adventure.sound.Sound lockedSound = net.kyori.adventure.sound.Sound.sound(org.bukkit.Sound.BLOCK_CHEST_LOCKED, net.kyori.adventure.sound.Sound.Source.BLOCK, 1.0F, 1.0F); -+ final io.papermc.paper.event.block.BlockLockCheckEvent event = new io.papermc.paper.event.block.BlockLockCheckEvent(block, serverPlayer.getBukkitEntity(), lockedMessage, lockedSound); -+ event.callEvent(); -+ if (event.getResult() == org.bukkit.event.Event.Result.ALLOW) { -+ return true; -+ } else if (event.getResult() == org.bukkit.event.Event.Result.DENY || (!player.isSpectator() && !lock.unlocksWith(event.isUsingCustomKeyItemStack() ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getKeyItem()) : player.getMainHandItem()))) { -+ if (event.getLockedMessage() != null) { -+ event.getPlayer().sendActionBar(event.getLockedMessage()); -+ } -+ if (event.getLockedSound() != null) { -+ event.getPlayer().playSound(event.getLockedSound()); -+ } -+ return false; -+ } else { -+ return true; -+ } -+ } else { // logic below is replaced by logic above -+ // Paper end - Add BlockLockCheckEvent - if (!player.isSpectator() && !lock.unlocksWith(player.getMainHandItem())) { -- player.displayClientMessage(Component.translatable("container.isLocked", containerName), true); -+ player.displayClientMessage(Component.translatable("container.isLocked", containerName), true); // Paper - diff on change - player.playNotifySound(SoundEvents.CHEST_LOCKED, SoundSource.BLOCKS, 1.0F, 1.0F); - return false; - } else { - return true; - } -+ } // Paper - Add BlockLockCheckEvent - } - - protected abstract NonNullList getItems(); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index edd6017937a7f20a1b43fa15204ec130b524b52b..2a7d896dd9a02acf6e3596e2e2e7ed50f4b88377 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -472,7 +472,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - @Nullable - @Override - public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory, Player player) { -- return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName()) ? new BeaconMenu(syncId, playerInventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())) : null; -+ return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName(), this) ? new BeaconMenu(syncId, playerInventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())) : null; // Paper - Add BlockLockCheckEvent - } - - @Override diff --git a/patches/server/0772-Add-Sneaking-API-for-Entities.patch b/patches/server/0772-Add-Sneaking-API-for-Entities.patch new file mode 100644 index 0000000000..40141ca398 --- /dev/null +++ b/patches/server/0772-Add-Sneaking-API-for-Entities.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dawon +Date: Wed, 19 Oct 2022 23:31:53 +0200 +Subject: [PATCH] Add Sneaking API for Entities + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 01513cd747a0e18e3839e83bf5795aadb7d1e0e9..8a715159917950091e8efd48eaca6a54488fb896 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -875,6 +875,18 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return Pose.values()[this.getHandle().getPose().ordinal()]; + } + ++ // Paper start ++ @Override ++ public void setSneaking(boolean sneak) { ++ this.getHandle().setShiftKeyDown(sneak); ++ } ++ ++ @Override ++ public boolean isSneaking() { ++ return this.getHandle().isShiftKeyDown(); ++ } ++ // Paper end ++ + @Override + public SpawnCategory getSpawnCategory() { + return CraftSpawnCategory.toBukkit(this.getHandle().getType().getCategory()); diff --git a/patches/server/0773-Add-Sneaking-API-for-Entities.patch b/patches/server/0773-Add-Sneaking-API-for-Entities.patch deleted file mode 100644 index 40141ca398..0000000000 --- a/patches/server/0773-Add-Sneaking-API-for-Entities.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dawon -Date: Wed, 19 Oct 2022 23:31:53 +0200 -Subject: [PATCH] Add Sneaking API for Entities - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 01513cd747a0e18e3839e83bf5795aadb7d1e0e9..8a715159917950091e8efd48eaca6a54488fb896 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -875,6 +875,18 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return Pose.values()[this.getHandle().getPose().ordinal()]; - } - -+ // Paper start -+ @Override -+ public void setSneaking(boolean sneak) { -+ this.getHandle().setShiftKeyDown(sneak); -+ } -+ -+ @Override -+ public boolean isSneaking() { -+ return this.getHandle().isShiftKeyDown(); -+ } -+ // Paper end -+ - @Override - public SpawnCategory getSpawnCategory() { - return CraftSpawnCategory.toBukkit(this.getHandle().getType().getCategory()); diff --git a/patches/server/0773-Improve-logging-and-errors.patch b/patches/server/0773-Improve-logging-and-errors.patch new file mode 100644 index 0000000000..1388f4a8b5 --- /dev/null +++ b/patches/server/0773-Improve-logging-and-errors.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 14 Dec 2022 15:52:11 -0800 +Subject: [PATCH] Improve logging and errors + +Co-authored-by: Jason Penilla <11360596+jpenilla@users.noreply.github.com> + +diff --git a/src/main/java/net/minecraft/advancements/AdvancementTree.java b/src/main/java/net/minecraft/advancements/AdvancementTree.java +index 2665170b8391a77d6b3fb7ae7b5ccfc0be65acd7..e00d4e0896c0163c43d79af63338de67c7cb0dc4 100644 +--- a/src/main/java/net/minecraft/advancements/AdvancementTree.java ++++ b/src/main/java/net/minecraft/advancements/AdvancementTree.java +@@ -35,7 +35,7 @@ public class AdvancementTree { + this.remove(advancementnode1); + } + +- AdvancementTree.LOGGER.info("Forgot about advancement {}", advancement.holder()); ++ AdvancementTree.LOGGER.debug("Forgot about advancement {}", advancement.holder()); // Paper - Improve logging and errors + this.nodes.remove(advancement.holder().id()); + if (advancement.parent() == null) { + this.roots.remove(advancement); +@@ -77,7 +77,7 @@ public class AdvancementTree { + } + } + +- // AdvancementTree.LOGGER.info("Loaded {} advancements", this.nodes.size()); // CraftBukkit - moved to AdvancementDataWorld#reload ++ // AdvancementTree.LOGGER.info("Loaded {} advancements", this.nodes.size()); // CraftBukkit - moved to AdvancementDataWorld#reload // Paper - Improve logging and errors; you say it was moved... but it wasn't :) it should be moved however, since this is called when the API creates an advancement + } + + private boolean tryInsert(AdvancementHolder advancement) { +diff --git a/src/main/java/net/minecraft/server/ServerAdvancementManager.java b/src/main/java/net/minecraft/server/ServerAdvancementManager.java +index 0828deee077a08db8e3fe5c870f9c242b4c550cf..5c8cf225d936617b6c8d265527a19bdfa371a93b 100644 +--- a/src/main/java/net/minecraft/server/ServerAdvancementManager.java ++++ b/src/main/java/net/minecraft/server/ServerAdvancementManager.java +@@ -53,6 +53,7 @@ public class ServerAdvancementManager extends SimpleJsonResourceReloadListener directoryStream = Files.newDirectoryStream(path)) { + for (Path path2 : directoryStream) { + String string = path2.getFileName().toString(); ++ // Paper start - Improve logging and errors ++ if (!Files.isDirectory(path2)) { ++ LOGGER.error("Invalid directory entry: {} in {}.", string, this.root, new java.nio.file.NotDirectoryException(string)); ++ continue; ++ } ++ // Paper end - Improve logging and errors + if (ResourceLocation.isValidNamespace(string)) { + set.add(string); + } else { +diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java +index 46787d68eadc789c3409c0845f3fb0be713c70cc..51ae8eddadc87b143b93521a3cef374f1e3a24dc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java ++++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java +@@ -44,6 +44,7 @@ import org.bukkit.material.MaterialData; + */ + @Deprecated + public final class CraftLegacy { ++ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper - Improve logging and errors + + private static final Map SPAWN_EGGS = new HashMap<>(); + private static final Set whitelistedStates = new HashSet<>(Arrays.asList("explode", "check_decay", "decayable", "facing")); +@@ -264,7 +265,7 @@ public final class CraftLegacy { + } + + static { +- System.err.println("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); ++ LOGGER.warn("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); // Paper - Improve logging and errors; doesn't need to be an error + if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) { + new Exception().printStackTrace(); + } diff --git a/patches/server/0774-Improve-PortalEvents.patch b/patches/server/0774-Improve-PortalEvents.patch new file mode 100644 index 0000000000..a4cf96f882 --- /dev/null +++ b/patches/server/0774-Improve-PortalEvents.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 15 Dec 2022 10:33:39 -0800 +Subject: [PATCH] Improve PortalEvents + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 25b1e8bec23465f0e9a17f156bdff7fe716db84c..f05a9fd321a4af28e9771bbf39d73f80dd4160c9 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1561,7 +1561,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + Location enter = this.getBukkitEntity().getLocation(); + PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); +- Location exit = (worldserver == null) ? null : CraftLocation.toBukkit(absolutePosition.position(), worldserver.getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); ++ Location exit = /* (worldserver == null) ? null : // Paper - always non-null */CraftLocation.toBukkit(absolutePosition.position(), worldserver.getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); + PlayerTeleportEvent tpEvent = new PlayerTeleportEvent(this.getBukkitEntity(), enter, exit, teleportTarget.cause()); + // Paper start - gateway-specific teleport event + if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.serverLevel().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 47a2cd3ea7c88681929351c6db9090149e2c4f2e..37419819758574631486886307f3133a8a3c1c36 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3740,7 +3740,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); + Location enter = bukkitEntity.getLocation(); + +- EntityPortalEvent event = new EntityPortalEvent(bukkitEntity, enter, exit, searchRadius, true, creationRadius); ++ // Paper start ++ final org.bukkit.PortalType portalType = switch (cause) { ++ case END_PORTAL -> org.bukkit.PortalType.ENDER; ++ case NETHER_PORTAL -> org.bukkit.PortalType.NETHER; ++ case END_GATEWAY -> org.bukkit.PortalType.END_GATEWAY; // not actually used yet ++ default -> org.bukkit.PortalType.CUSTOM; ++ }; ++ EntityPortalEvent event = new EntityPortalEvent(bukkitEntity, enter, exit, searchRadius, true, creationRadius, portalType); ++ // Paper end + event.getEntity().getServer().getPluginManager().callEvent(event); + if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null || !entity.isAlive()) { + return null; +diff --git a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java +index bb4800c60ac05f2db8821737b2b884ea99b64799..a7a21f071161fb7e73a046717d2462f871ab653c 100644 +--- a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java +@@ -94,6 +94,10 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { + protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + if (entity.canUsePortal(false)) { ++ // Paper start - call EntityPortalEnterEvent ++ org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.END_GATEWAY); // Paper - add portal type ++ if (!event.callEvent()) return; ++ // Paper end - call EntityPortalEnterEvent + BlockEntity tileentity = world.getBlockEntity(pos); + + if (!world.isClientSide && tileentity instanceof TheEndGatewayBlockEntity) { +diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java +index 6ed6c2123ed4c54f191ed8cf6da72109fb95eb69..4aa14f975e1ceedf3d4a427e0daefb58b12fcafe 100644 +--- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java +@@ -71,8 +71,9 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + if (entity.canUsePortal(false)) { + // CraftBukkit start - Entity in portal +- EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); ++ EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.ENDER); // Paper - add portal type + world.getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) return; // Paper - make cancellable + // CraftBukkit end + if (!world.isClientSide && world.dimension() == Level.END && entity instanceof ServerPlayer) { + ServerPlayer entityplayer = (ServerPlayer) entity; +@@ -95,7 +96,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { + ServerLevel worldserver1 = world.getServer().getLevel(resourcekey); + + if (worldserver1 == null) { +- return new TeleportTransition(PlayerTeleportEvent.TeleportCause.END_PORTAL); // CraftBukkit- always fire event in case plugins wish to change it ++ return null; // Paper - keep previous behavior of not firing PlayerTeleportEvent if the target world doesn't exist + } else { + boolean flag = resourcekey == Level.END; + BlockPos blockposition1 = flag ? ServerLevel.END_SPAWN_POINT : worldserver1.getSharedSpawnPos(); +diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +index fb361eac03c16ecee02219ff0524cce2292c7976..2b31bf586c1c0bd393d2aa8d0b6635dd9f22f21c 100644 +--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -118,8 +118,9 @@ public class NetherPortalBlock extends Block implements Portal { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + if (entity.canUsePortal(false)) { + // CraftBukkit start - Entity in portal +- EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); ++ EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.NETHER); // Paper - add portal type + world.getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) return; // Paper - make cancellable + // CraftBukkit end + entity.setAsInsidePortal(this, pos); + } +@@ -151,7 +152,7 @@ public class NetherPortalBlock extends Block implements Portal { + // Paper end - Add EntityPortalReadyEvent + + if (worldserver1 == null) { +- return new TeleportTransition(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // always fire event in case plugins wish to change it ++ return null; // Paper - keep previous behavior of not firing PlayerTeleportEvent if the target world doesn't exist + } else { + boolean flag = worldserver1.getTypeKey() == LevelStem.NETHER; + // CraftBukkit end diff --git a/patches/server/0774-Improve-logging-and-errors.patch b/patches/server/0774-Improve-logging-and-errors.patch deleted file mode 100644 index d8fff73a33..0000000000 --- a/patches/server/0774-Improve-logging-and-errors.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 14 Dec 2022 15:52:11 -0800 -Subject: [PATCH] Improve logging and errors - -Co-authored-by: Jason Penilla <11360596+jpenilla@users.noreply.github.com> - -diff --git a/src/main/java/net/minecraft/advancements/AdvancementTree.java b/src/main/java/net/minecraft/advancements/AdvancementTree.java -index 2665170b8391a77d6b3fb7ae7b5ccfc0be65acd7..e00d4e0896c0163c43d79af63338de67c7cb0dc4 100644 ---- a/src/main/java/net/minecraft/advancements/AdvancementTree.java -+++ b/src/main/java/net/minecraft/advancements/AdvancementTree.java -@@ -35,7 +35,7 @@ public class AdvancementTree { - this.remove(advancementnode1); - } - -- AdvancementTree.LOGGER.info("Forgot about advancement {}", advancement.holder()); -+ AdvancementTree.LOGGER.debug("Forgot about advancement {}", advancement.holder()); // Paper - Improve logging and errors - this.nodes.remove(advancement.holder().id()); - if (advancement.parent() == null) { - this.roots.remove(advancement); -@@ -77,7 +77,7 @@ public class AdvancementTree { - } - } - -- // AdvancementTree.LOGGER.info("Loaded {} advancements", this.nodes.size()); // CraftBukkit - moved to AdvancementDataWorld#reload -+ // AdvancementTree.LOGGER.info("Loaded {} advancements", this.nodes.size()); // CraftBukkit - moved to AdvancementDataWorld#reload // Paper - Improve logging and errors; you say it was moved... but it wasn't :) it should be moved however, since this is called when the API creates an advancement - } - - private boolean tryInsert(AdvancementHolder advancement) { -diff --git a/src/main/java/net/minecraft/server/ServerAdvancementManager.java b/src/main/java/net/minecraft/server/ServerAdvancementManager.java -index 0828deee077a08db8e3fe5c870f9c242b4c550cf..5c8cf225d936617b6c8d265527a19bdfa371a93b 100644 ---- a/src/main/java/net/minecraft/server/ServerAdvancementManager.java -+++ b/src/main/java/net/minecraft/server/ServerAdvancementManager.java -@@ -53,6 +53,7 @@ public class ServerAdvancementManager extends SimpleJsonResourceReloadListener directoryStream = Files.newDirectoryStream(path)) { - for (Path path2 : directoryStream) { - String string = path2.getFileName().toString(); -+ // Paper start - Improve logging and errors -+ if (!Files.isDirectory(path2)) { -+ LOGGER.error("Invalid directory entry: {} in {}.", string, this.root, new java.nio.file.NotDirectoryException(string)); -+ continue; -+ } -+ // Paper end - Improve logging and errors - if (ResourceLocation.isValidNamespace(string)) { - set.add(string); - } else { -diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java -index 46787d68eadc789c3409c0845f3fb0be713c70cc..51ae8eddadc87b143b93521a3cef374f1e3a24dc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java -+++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java -@@ -44,6 +44,7 @@ import org.bukkit.material.MaterialData; - */ - @Deprecated - public final class CraftLegacy { -+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper - Improve logging and errors - - private static final Map SPAWN_EGGS = new HashMap<>(); - private static final Set whitelistedStates = new HashSet<>(Arrays.asList("explode", "check_decay", "decayable", "facing")); -@@ -264,7 +265,7 @@ public final class CraftLegacy { - } - - static { -- System.err.println("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); -+ LOGGER.warn("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); // Paper - Improve logging and errors; doesn't need to be an error - if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) { - new Exception().printStackTrace(); - } diff --git a/patches/server/0775-Add-config-option-for-spider-worldborder-climbing.patch b/patches/server/0775-Add-config-option-for-spider-worldborder-climbing.patch new file mode 100644 index 0000000000..6d4efc38b6 --- /dev/null +++ b/patches/server/0775-Add-config-option-for-spider-worldborder-climbing.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 27 Oct 2022 15:35:47 +0200 +Subject: [PATCH] Add config option for spider worldborder climbing + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java +index ba4dfa26f4d54abe9ecbacfe1f409a34fb769579..6c2d4c2163cf299c0943af21d4dc367b5677c089 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Spider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java +@@ -82,7 +82,7 @@ public class Spider extends Monster { + public void tick() { + super.tick(); + if (!this.level().isClientSide) { +- this.setClimbing(this.horizontalCollision); ++ this.setClimbing(this.horizontalCollision && (this.level().paperConfig().entities.behavior.allowSpiderWorldBorderClimbing || !(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isCollidingWithBorder(this.level().getWorldBorder(), this.getBoundingBox().inflate(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) && this.level().getWorldBorder().isInsideCloseToBorder(this, this.getBoundingBox())))); // Paper - Add config option for spider worldborder climbing (Inflate by +EPSILON as collision will just barely place us outside border) + } + + } diff --git a/patches/server/0775-Improve-PortalEvents.patch b/patches/server/0775-Improve-PortalEvents.patch deleted file mode 100644 index a4cf96f882..0000000000 --- a/patches/server/0775-Improve-PortalEvents.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 15 Dec 2022 10:33:39 -0800 -Subject: [PATCH] Improve PortalEvents - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 25b1e8bec23465f0e9a17f156bdff7fe716db84c..f05a9fd321a4af28e9771bbf39d73f80dd4160c9 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1561,7 +1561,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - Location enter = this.getBukkitEntity().getLocation(); - PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); -- Location exit = (worldserver == null) ? null : CraftLocation.toBukkit(absolutePosition.position(), worldserver.getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); -+ Location exit = /* (worldserver == null) ? null : // Paper - always non-null */CraftLocation.toBukkit(absolutePosition.position(), worldserver.getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); - PlayerTeleportEvent tpEvent = new PlayerTeleportEvent(this.getBukkitEntity(), enter, exit, teleportTarget.cause()); - // Paper start - gateway-specific teleport event - if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.serverLevel().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 47a2cd3ea7c88681929351c6db9090149e2c4f2e..37419819758574631486886307f3133a8a3c1c36 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3740,7 +3740,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); - Location enter = bukkitEntity.getLocation(); - -- EntityPortalEvent event = new EntityPortalEvent(bukkitEntity, enter, exit, searchRadius, true, creationRadius); -+ // Paper start -+ final org.bukkit.PortalType portalType = switch (cause) { -+ case END_PORTAL -> org.bukkit.PortalType.ENDER; -+ case NETHER_PORTAL -> org.bukkit.PortalType.NETHER; -+ case END_GATEWAY -> org.bukkit.PortalType.END_GATEWAY; // not actually used yet -+ default -> org.bukkit.PortalType.CUSTOM; -+ }; -+ EntityPortalEvent event = new EntityPortalEvent(bukkitEntity, enter, exit, searchRadius, true, creationRadius, portalType); -+ // Paper end - event.getEntity().getServer().getPluginManager().callEvent(event); - if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null || !entity.isAlive()) { - return null; -diff --git a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -index bb4800c60ac05f2db8821737b2b884ea99b64799..a7a21f071161fb7e73a046717d2462f871ab653c 100644 ---- a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -@@ -94,6 +94,10 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { - protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (entity.canUsePortal(false)) { -+ // Paper start - call EntityPortalEnterEvent -+ org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.END_GATEWAY); // Paper - add portal type -+ if (!event.callEvent()) return; -+ // Paper end - call EntityPortalEnterEvent - BlockEntity tileentity = world.getBlockEntity(pos); - - if (!world.isClientSide && tileentity instanceof TheEndGatewayBlockEntity) { -diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -index 6ed6c2123ed4c54f191ed8cf6da72109fb95eb69..4aa14f975e1ceedf3d4a427e0daefb58b12fcafe 100644 ---- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -@@ -71,8 +71,9 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (entity.canUsePortal(false)) { - // CraftBukkit start - Entity in portal -- EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); -+ EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.ENDER); // Paper - add portal type - world.getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) return; // Paper - make cancellable - // CraftBukkit end - if (!world.isClientSide && world.dimension() == Level.END && entity instanceof ServerPlayer) { - ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -95,7 +96,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { - ServerLevel worldserver1 = world.getServer().getLevel(resourcekey); - - if (worldserver1 == null) { -- return new TeleportTransition(PlayerTeleportEvent.TeleportCause.END_PORTAL); // CraftBukkit- always fire event in case plugins wish to change it -+ return null; // Paper - keep previous behavior of not firing PlayerTeleportEvent if the target world doesn't exist - } else { - boolean flag = resourcekey == Level.END; - BlockPos blockposition1 = flag ? ServerLevel.END_SPAWN_POINT : worldserver1.getSharedSpawnPos(); -diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -index fb361eac03c16ecee02219ff0524cce2292c7976..2b31bf586c1c0bd393d2aa8d0b6635dd9f22f21c 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -@@ -118,8 +118,9 @@ public class NetherPortalBlock extends Block implements Portal { - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (entity.canUsePortal(false)) { - // CraftBukkit start - Entity in portal -- EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); -+ EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.NETHER); // Paper - add portal type - world.getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) return; // Paper - make cancellable - // CraftBukkit end - entity.setAsInsidePortal(this, pos); - } -@@ -151,7 +152,7 @@ public class NetherPortalBlock extends Block implements Portal { - // Paper end - Add EntityPortalReadyEvent - - if (worldserver1 == null) { -- return new TeleportTransition(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // always fire event in case plugins wish to change it -+ return null; // Paper - keep previous behavior of not firing PlayerTeleportEvent if the target world doesn't exist - } else { - boolean flag = worldserver1.getTypeKey() == LevelStem.NETHER; - // CraftBukkit end diff --git a/patches/server/0776-Add-config-option-for-spider-worldborder-climbing.patch b/patches/server/0776-Add-config-option-for-spider-worldborder-climbing.patch deleted file mode 100644 index 6d4efc38b6..0000000000 --- a/patches/server/0776-Add-config-option-for-spider-worldborder-climbing.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 27 Oct 2022 15:35:47 +0200 -Subject: [PATCH] Add config option for spider worldborder climbing - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java -index ba4dfa26f4d54abe9ecbacfe1f409a34fb769579..6c2d4c2163cf299c0943af21d4dc367b5677c089 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Spider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java -@@ -82,7 +82,7 @@ public class Spider extends Monster { - public void tick() { - super.tick(); - if (!this.level().isClientSide) { -- this.setClimbing(this.horizontalCollision); -+ this.setClimbing(this.horizontalCollision && (this.level().paperConfig().entities.behavior.allowSpiderWorldBorderClimbing || !(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isCollidingWithBorder(this.level().getWorldBorder(), this.getBoundingBox().inflate(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) && this.level().getWorldBorder().isInsideCloseToBorder(this, this.getBoundingBox())))); // Paper - Add config option for spider worldborder climbing (Inflate by +EPSILON as collision will just barely place us outside border) - } - - } diff --git a/patches/server/0776-Add-missing-SpigotConfig-logCommands-check.patch b/patches/server/0776-Add-missing-SpigotConfig-logCommands-check.patch new file mode 100644 index 0000000000..73e77aed11 --- /dev/null +++ b/patches/server/0776-Add-missing-SpigotConfig-logCommands-check.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NonSwag +Date: Thu, 8 Dec 2022 20:25:05 +0100 +Subject: [PATCH] Add missing SpigotConfig logCommands check + +Co-authored-by: david + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 345d5069d0ebb8ad74158334fd230d0ea64b909d..af8a513c2692b71ad56abce24048b61eb78d41c4 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2078,7 +2078,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + private void performUnsignedChatCommand(String command) { + // CraftBukkit start + String command1 = "/" + command; ++ if (org.spigotmc.SpigotConfig.logCommands) { // Paper - Add missing SpigotConfig logCommands check + ServerGamePacketListenerImpl.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command1); ++ } + + PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command1, new LazyPlayerSet(this.server)); + this.cserver.getPluginManager().callEvent(event); +@@ -2118,7 +2120,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + private void performSignedChatCommand(ServerboundChatCommandSignedPacket packet, LastSeenMessages lastSeenMessages) { + // CraftBukkit start + String command = "/" + packet.command(); ++ if (org.spigotmc.SpigotConfig.logCommands) { // Paper - Add missing SpigotConfig logCommands check + ServerGamePacketListenerImpl.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command); ++ } // Paper - Add missing SpigotConfig logCommands check + + PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command, new LazyPlayerSet(this.server)); + this.cserver.getPluginManager().callEvent(event); diff --git a/patches/server/0777-Add-missing-SpigotConfig-logCommands-check.patch b/patches/server/0777-Add-missing-SpigotConfig-logCommands-check.patch deleted file mode 100644 index 1bd83dc7d8..0000000000 --- a/patches/server/0777-Add-missing-SpigotConfig-logCommands-check.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NonSwag -Date: Thu, 8 Dec 2022 20:25:05 +0100 -Subject: [PATCH] Add missing SpigotConfig logCommands check - -Co-authored-by: david - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 6f3e25d41420b5e54721e88c84fd3194d6170b9a..59b64ea82c84ff7d9b9123473b4466ec01918cd2 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2078,7 +2078,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private void performUnsignedChatCommand(String command) { - // CraftBukkit start - String command1 = "/" + command; -+ if (org.spigotmc.SpigotConfig.logCommands) { // Paper - Add missing SpigotConfig logCommands check - ServerGamePacketListenerImpl.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command1); -+ } - - PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command1, new LazyPlayerSet(this.server)); - this.cserver.getPluginManager().callEvent(event); -@@ -2118,7 +2120,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private void performSignedChatCommand(ServerboundChatCommandSignedPacket packet, LastSeenMessages lastSeenMessages) { - // CraftBukkit start - String command = "/" + packet.command(); -+ if (org.spigotmc.SpigotConfig.logCommands) { // Paper - Add missing SpigotConfig logCommands check - ServerGamePacketListenerImpl.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + command); -+ } // Paper - Add missing SpigotConfig logCommands check - - PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command, new LazyPlayerSet(this.server)); - this.cserver.getPluginManager().callEvent(event); diff --git a/patches/server/0777-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch b/patches/server/0777-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch new file mode 100644 index 0000000000..581ad00ec1 --- /dev/null +++ b/patches/server/0777-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NonSwag +Date: Tue, 6 Dec 2022 23:04:21 +0100 +Subject: [PATCH] Fix NPE on Allay#stopDancing while not dancing + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java +index 1d04df8752af74ae73231922041d09df9d7492bb..c64918175ec08d20cde2bda9e0cac8b474385fe0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java +@@ -78,7 +78,7 @@ public class CraftAllay extends CraftCreature implements org.bukkit.entity.Allay + public void stopDancing() { + this.getHandle().forceDancing = false; + this.getHandle().jukeboxPos = null; +- this.getHandle().setJukeboxPlaying(null, false); ++ this.getHandle().setDancing(false); // Paper - Directly modify set dancing to avoid NPE + } + + @Override diff --git a/patches/server/0778-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch b/patches/server/0778-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch deleted file mode 100644 index 581ad00ec1..0000000000 --- a/patches/server/0778-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NonSwag -Date: Tue, 6 Dec 2022 23:04:21 +0100 -Subject: [PATCH] Fix NPE on Allay#stopDancing while not dancing - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java -index 1d04df8752af74ae73231922041d09df9d7492bb..c64918175ec08d20cde2bda9e0cac8b474385fe0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAllay.java -@@ -78,7 +78,7 @@ public class CraftAllay extends CraftCreature implements org.bukkit.entity.Allay - public void stopDancing() { - this.getHandle().forceDancing = false; - this.getHandle().jukeboxPos = null; -- this.getHandle().setJukeboxPlaying(null, false); -+ this.getHandle().setDancing(false); // Paper - Directly modify set dancing to avoid NPE - } - - @Override diff --git a/patches/server/0778-Flying-Fall-Damage.patch b/patches/server/0778-Flying-Fall-Damage.patch new file mode 100644 index 0000000000..a09b209fd2 --- /dev/null +++ b/patches/server/0778-Flying-Fall-Damage.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TreyRuffy +Date: Fri, 27 May 2022 02:26:08 -0600 +Subject: [PATCH] Flying Fall Damage + + +diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java +index 30e0a5fe3f9bd85d2b702c2c877c5682ed35d461..aca888c2f02b09ac6739bdc81b194c4527dd69f5 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -196,6 +196,7 @@ public abstract class Player extends LivingEntity { + private boolean ignoreFallDamageFromCurrentImpulse; + private int currentImpulseContextResetGraceTime; + public boolean affectsSpawning = true; // Paper - Affects Spawning API ++ public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage + + // CraftBukkit start + public boolean fauxSleeping; +@@ -1651,7 +1652,7 @@ public abstract class Player extends LivingEntity { + + @Override + public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { +- if (this.abilities.mayfly) { ++ if (this.abilities.mayfly && !this.flyingFallDamage.toBooleanOrElse(false)) { // Paper - flying fall damage + return false; + } else { + if (fallDistance >= 2.0F) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index f710776d2a81c426cbe75532b06da4f8b1ef4787..35722608d2c2d702429f5724732e8af39bb37488 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2611,6 +2611,19 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + this.getHandle().onUpdateAbilities(); + } + ++ // Paper start - flying fall damage ++ @Override ++ public void setFlyingFallDamage(@NotNull net.kyori.adventure.util.TriState flyingFallDamage) { ++ getHandle().flyingFallDamage = flyingFallDamage; ++ } ++ ++ @NotNull ++ @Override ++ public net.kyori.adventure.util.TriState hasFlyingFallDamage() { ++ return getHandle().flyingFallDamage; ++ } ++ // Paper end - flying fall damage ++ + @Override + public int getNoDamageTicks() { + if (this.getHandle().spawnInvulnerableTime > 0) { diff --git a/patches/server/0779-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch b/patches/server/0779-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch new file mode 100644 index 0000000000..c08dab2b2d --- /dev/null +++ b/patches/server/0779-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Tue, 11 Oct 2022 23:30:32 +0300 +Subject: [PATCH] Expose pre-collision moving velocity to + VehicleBlockCollisionEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 37419819758574631486886307f3133a8a3c1c36..0e52f67f0185cba47838f0a99a97b4d70314c8fa 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -968,6 +968,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public void move(MoverType type, Vec3 movement) { ++ final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity + if (this.noPhysics) { + this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); + } else { +@@ -1059,7 +1060,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + if (!bl.getType().isAir()) { +- VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl); ++ VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl, org.bukkit.craftbukkit.util.CraftVector.toBukkit(originalMovement)); // Paper - Expose pre-collision velocity + this.level.getCraftServer().getPluginManager().callEvent(event); + } + } diff --git a/patches/server/0779-Flying-Fall-Damage.patch b/patches/server/0779-Flying-Fall-Damage.patch deleted file mode 100644 index a09b209fd2..0000000000 --- a/patches/server/0779-Flying-Fall-Damage.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TreyRuffy -Date: Fri, 27 May 2022 02:26:08 -0600 -Subject: [PATCH] Flying Fall Damage - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 30e0a5fe3f9bd85d2b702c2c877c5682ed35d461..aca888c2f02b09ac6739bdc81b194c4527dd69f5 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -196,6 +196,7 @@ public abstract class Player extends LivingEntity { - private boolean ignoreFallDamageFromCurrentImpulse; - private int currentImpulseContextResetGraceTime; - public boolean affectsSpawning = true; // Paper - Affects Spawning API -+ public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage - - // CraftBukkit start - public boolean fauxSleeping; -@@ -1651,7 +1652,7 @@ public abstract class Player extends LivingEntity { - - @Override - public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { -- if (this.abilities.mayfly) { -+ if (this.abilities.mayfly && !this.flyingFallDamage.toBooleanOrElse(false)) { // Paper - flying fall damage - return false; - } else { - if (fallDistance >= 2.0F) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index f710776d2a81c426cbe75532b06da4f8b1ef4787..35722608d2c2d702429f5724732e8af39bb37488 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2611,6 +2611,19 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - this.getHandle().onUpdateAbilities(); - } - -+ // Paper start - flying fall damage -+ @Override -+ public void setFlyingFallDamage(@NotNull net.kyori.adventure.util.TriState flyingFallDamage) { -+ getHandle().flyingFallDamage = flyingFallDamage; -+ } -+ -+ @NotNull -+ @Override -+ public net.kyori.adventure.util.TriState hasFlyingFallDamage() { -+ return getHandle().flyingFallDamage; -+ } -+ // Paper end - flying fall damage -+ - @Override - public int getNoDamageTicks() { - if (this.getHandle().spawnInvulnerableTime > 0) { diff --git a/patches/server/0780-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch b/patches/server/0780-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch deleted file mode 100644 index c08dab2b2d..0000000000 --- a/patches/server/0780-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SoSeDiK -Date: Tue, 11 Oct 2022 23:30:32 +0300 -Subject: [PATCH] Expose pre-collision moving velocity to - VehicleBlockCollisionEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 37419819758574631486886307f3133a8a3c1c36..0e52f67f0185cba47838f0a99a97b4d70314c8fa 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -968,6 +968,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public void move(MoverType type, Vec3 movement) { -+ final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity - if (this.noPhysics) { - this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); - } else { -@@ -1059,7 +1060,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - if (!bl.getType().isAir()) { -- VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl); -+ VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl, org.bukkit.craftbukkit.util.CraftVector.toBukkit(originalMovement)); // Paper - Expose pre-collision velocity - this.level.getCraftServer().getPluginManager().callEvent(event); - } - } diff --git a/patches/server/0780-config-for-disabling-entity-tag-tags.patch b/patches/server/0780-config-for-disabling-entity-tag-tags.patch new file mode 100644 index 0000000000..59c33843ce --- /dev/null +++ b/patches/server/0780-config-for-disabling-entity-tag-tags.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 15 Sep 2021 14:52:42 -0700 +Subject: [PATCH] config for disabling entity tag tags + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java +index 989b766bc166141a391e0a7c1a5eb815e20acfac..64dc0bd1900575e40ac72a98c6df371223bd244c 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -569,6 +569,16 @@ public class EntityType implements FeatureElement, EntityTypeT + + if (minecraftserver != null && entity != null) { + if (world.isClientSide || !entity.onlyOpCanSetNbt() || player != null && minecraftserver.getPlayerList().isOp(player.getGameProfile())) { ++ // Paper start - filter out protected tags ++ if (player == null || !player.getBukkitEntity().hasPermission("minecraft.nbt.place")) { ++ nbt = nbt.update((compound) -> { ++ for (net.minecraft.commands.arguments.NbtPathArgument.NbtPath tag : world.paperConfig().entities.spawning.filteredEntityTagNbtPaths) { ++ tag.remove(compound); ++ } ++ }); ++ } ++ // Paper end - filter out protected tags ++ + nbt.loadInto(entity); + } + } diff --git a/patches/server/0781-Use-single-player-info-update-packet-on-join.patch b/patches/server/0781-Use-single-player-info-update-packet-on-join.patch new file mode 100644 index 0000000000..c1e89be3e8 --- /dev/null +++ b/patches/server/0781-Use-single-player-info-update-packet-on-join.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 8 Jan 2023 17:38:28 -0800 +Subject: [PATCH] Use single player info update packet on join + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index af8a513c2692b71ad56abce24048b61eb78d41c4..5802bca38fdeccbc1353990ecb425034f86e8332 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3486,7 +3486,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.signedMessageDecoder = session.createMessageDecoder(this.player.getUUID()); + this.chatMessageChain.append(() -> { + this.player.setChatSession(session); +- this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player))); ++ this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player)), this.player); // Paper - Use single player info update packet on join + }); + } + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 6332d5e281bb355bee1a112d11e96ee26e337ebf..af0ea5b5bbc35cced959beb3ecb576fff46c6a51 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -364,6 +364,7 @@ public abstract class PlayerList { + // CraftBukkit start - sendAll above replaced with this loop + ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); + ++ final List onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join + for (int i = 0; i < this.players.size(); ++i) { + ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i); + +@@ -371,12 +372,17 @@ public abstract class PlayerList { + entityplayer1.connection.send(packet); + } + +- if (!bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { ++ if (entityplayer1 == player || !bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { // Paper - Use single player info update packet on join; Don't include joining player + continue; + } + +- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1))); ++ onlinePlayers.add(entityplayer1); // Paper - Use single player info update packet on join + } ++ // Paper start - Use single player info update packet on join ++ if (!onlinePlayers.isEmpty()) { ++ player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers)); ++ } ++ // Paper end - Use single player info update packet on join + player.sentListPacket = true; + player.supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready + ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now diff --git a/patches/server/0781-config-for-disabling-entity-tag-tags.patch b/patches/server/0781-config-for-disabling-entity-tag-tags.patch deleted file mode 100644 index f1526d5e31..0000000000 --- a/patches/server/0781-config-for-disabling-entity-tag-tags.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 15 Sep 2021 14:52:42 -0700 -Subject: [PATCH] config for disabling entity tag tags - - -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index e5dc6f868f090d1957306a6389d85cf9dbbc444d..ca9e63942f3cb8986456410b2a77aafc6541aad2 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -578,6 +578,16 @@ public class EntityType implements FeatureElement, EntityTypeT - - if (minecraftserver != null && entity != null) { - if (world.isClientSide || !entity.onlyOpCanSetNbt() || player != null && minecraftserver.getPlayerList().isOp(player.getGameProfile())) { -+ // Paper start - filter out protected tags -+ if (player == null || !player.getBukkitEntity().hasPermission("minecraft.nbt.place")) { -+ nbt = nbt.update((compound) -> { -+ for (net.minecraft.commands.arguments.NbtPathArgument.NbtPath tag : world.paperConfig().entities.spawning.filteredEntityTagNbtPaths) { -+ tag.remove(compound); -+ } -+ }); -+ } -+ // Paper end - filter out protected tags -+ - nbt.loadInto(entity); - } - } diff --git a/patches/server/0782-Correctly-shrink-items-during-EntityResurrectEvent.patch b/patches/server/0782-Correctly-shrink-items-during-EntityResurrectEvent.patch new file mode 100644 index 0000000000..b778104720 --- /dev/null +++ b/patches/server/0782-Correctly-shrink-items-during-EntityResurrectEvent.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bjarne Koll +Date: Tue, 10 Jan 2023 21:06:42 +0100 +Subject: [PATCH] Correctly shrink items during EntityResurrectEvent + +The EntityResurrectEvent logic is supposed to locate a totem of undying +in any of the interaction slots of the player inventory and then, if the +called EntityResurrectEvent is not cancelled, shrink that item by 1, +usually reducing it to zero. + +For this, the logic iterates over the items in the interaction slots and +breaks out the loop if a totem of undying was found. +However, even if no totem of undying was found, the iteration item stack +variable remains as a refernce to the last interaction slot probed. + +Plugins uncancelling a EntityResurrectEvent, which is published +pre-cancelled to listeners if no totem of undying could be found, +would hence cause the server logic to shrink completely unrelated items +found in, at the writing of this patch, the players off hand slot. + +This patch corrects this behaviour by only shrinking the item if a totem +of undying was found and the event was called uncancelled. + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 8b0a764984f886b711cb337a7f70608167916bf3..9ef5c617cb05f08758105772b9124f6c318b5c17 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1672,7 +1672,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.level().getCraftServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { +- if (!itemstack1.isEmpty()) { ++ if (!itemstack1.isEmpty() && itemstack != null) { // Paper - only reduce item if actual totem was found + itemstack1.shrink(1); + } + if (itemstack != null && this instanceof ServerPlayer) { diff --git a/patches/server/0782-Use-single-player-info-update-packet-on-join.patch b/patches/server/0782-Use-single-player-info-update-packet-on-join.patch deleted file mode 100644 index 68e488cbf6..0000000000 --- a/patches/server/0782-Use-single-player-info-update-packet-on-join.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 8 Jan 2023 17:38:28 -0800 -Subject: [PATCH] Use single player info update packet on join - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 59b64ea82c84ff7d9b9123473b4466ec01918cd2..51f4d1e5c02c516b5c57095d35348ba53f5b3193 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3489,7 +3489,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.signedMessageDecoder = session.createMessageDecoder(this.player.getUUID()); - this.chatMessageChain.append(() -> { - this.player.setChatSession(session); -- this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player))); -+ this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player)), this.player); // Paper - Use single player info update packet on join - }); - } - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 61c37bf5f75207085f22093e48986dab8231e1c1..f9212fc2db00531da1618780e231e8ad21285907 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -365,6 +365,7 @@ public abstract class PlayerList { - // CraftBukkit start - sendAll above replaced with this loop - ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); - -+ final List onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join - for (int i = 0; i < this.players.size(); ++i) { - ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i); - -@@ -372,12 +373,17 @@ public abstract class PlayerList { - entityplayer1.connection.send(packet); - } - -- if (!bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { -+ if (entityplayer1 == player || !bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { // Paper - Use single player info update packet on join; Don't include joining player - continue; - } - -- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1))); -+ onlinePlayers.add(entityplayer1); // Paper - Use single player info update packet on join - } -+ // Paper start - Use single player info update packet on join -+ if (!onlinePlayers.isEmpty()) { -+ player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers)); -+ } -+ // Paper end - Use single player info update packet on join - player.sentListPacket = true; - player.supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready - ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now diff --git a/patches/server/0783-Correctly-shrink-items-during-EntityResurrectEvent.patch b/patches/server/0783-Correctly-shrink-items-during-EntityResurrectEvent.patch deleted file mode 100644 index c14b325882..0000000000 --- a/patches/server/0783-Correctly-shrink-items-during-EntityResurrectEvent.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bjarne Koll -Date: Tue, 10 Jan 2023 21:06:42 +0100 -Subject: [PATCH] Correctly shrink items during EntityResurrectEvent - -The EntityResurrectEvent logic is supposed to locate a totem of undying -in any of the interaction slots of the player inventory and then, if the -called EntityResurrectEvent is not cancelled, shrink that item by 1, -usually reducing it to zero. - -For this, the logic iterates over the items in the interaction slots and -breaks out the loop if a totem of undying was found. -However, even if no totem of undying was found, the iteration item stack -variable remains as a refernce to the last interaction slot probed. - -Plugins uncancelling a EntityResurrectEvent, which is published -pre-cancelled to listeners if no totem of undying could be found, -would hence cause the server logic to shrink completely unrelated items -found in, at the writing of this patch, the players off hand slot. - -This patch corrects this behaviour by only shrinking the item if a totem -of undying was found and the event was called uncancelled. - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 5520d0cdd5af75a6188a68f809aafb6c5880878a..da42691504177e1e2614db777cbe346f73725eda 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1674,7 +1674,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.level().getCraftServer().getPluginManager().callEvent(event); - - if (!event.isCancelled()) { -- if (!itemstack1.isEmpty()) { -+ if (!itemstack1.isEmpty() && itemstack != null) { // Paper - only reduce item if actual totem was found - itemstack1.shrink(1); - } - if (itemstack != null && this instanceof ServerPlayer) { diff --git a/patches/server/0783-Win-Screen-API.patch b/patches/server/0783-Win-Screen-API.patch new file mode 100644 index 0000000000..8412d997bc --- /dev/null +++ b/patches/server/0783-Win-Screen-API.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lama06 +Date: Sat, 21 Jan 2023 13:53:23 +0100 +Subject: [PATCH] Win Screen API + +== AT == +public net.minecraft.server.level.ServerPlayer seenCredits + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 35722608d2c2d702429f5724732e8af39bb37488..83e29f518a57bd2eb4113d5b93cdf47af119c715 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1322,6 +1322,25 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + this.getHandle().connection.send(packet); + } + ++ // Paper start ++ @Override ++ public void showWinScreen() { ++ if (getHandle().connection == null) return; ++ var packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1); ++ getHandle().connection.send(packet); ++ } ++ ++ @Override ++ public boolean hasSeenWinScreen() { ++ return getHandle().seenCredits; ++ } ++ ++ @Override ++ public void setHasSeenWinScreen(boolean hasSeenWinScreen) { ++ getHandle().seenCredits = hasSeenWinScreen; ++ } ++ // Paper end ++ + @Override + public void setRotation(float yaw, float pitch) { + // Paper start - Teleport API diff --git a/patches/server/0784-Remove-CraftItemStack-setAmount-null-assignment.patch b/patches/server/0784-Remove-CraftItemStack-setAmount-null-assignment.patch new file mode 100644 index 0000000000..aa0acd564f --- /dev/null +++ b/patches/server/0784-Remove-CraftItemStack-setAmount-null-assignment.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josh Roy +Date: Mon, 23 Jan 2023 19:19:01 -0500 +Subject: [PATCH] Remove CraftItemStack#setAmount null assignment + +This creates a problem with Paper's item serialization +api where deserialized items, which are internally +created as a CraftItemStack, will be completely lost if +#setAmount(0) is invoked (since the underlying handle +is set to null), while a regular Bukkit ItemStack +simply sets the amount field to zero, retaining the +item's data. + +Vanilla treats items with zero amounts the same as items +with less than zero amounts, so this code doesn't create +a problem with operations on the vanilla ItemStack. + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 502be683e8b04a9966043c9bee9d9fe793b12ef5..134db8c2dd72d0651fc889cc8931e7c971f62deb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -198,7 +198,7 @@ public final class CraftItemStack extends ItemStack { + } + + this.handle.setCount(amount); +- if (amount == 0) { ++ if (false && amount == 0) { // Paper - remove CraftItemStack#setAmount null assignment + this.handle = null; + } + } diff --git a/patches/server/0784-Win-Screen-API.patch b/patches/server/0784-Win-Screen-API.patch deleted file mode 100644 index 8412d997bc..0000000000 --- a/patches/server/0784-Win-Screen-API.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lama06 -Date: Sat, 21 Jan 2023 13:53:23 +0100 -Subject: [PATCH] Win Screen API - -== AT == -public net.minecraft.server.level.ServerPlayer seenCredits - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 35722608d2c2d702429f5724732e8af39bb37488..83e29f518a57bd2eb4113d5b93cdf47af119c715 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1322,6 +1322,25 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - this.getHandle().connection.send(packet); - } - -+ // Paper start -+ @Override -+ public void showWinScreen() { -+ if (getHandle().connection == null) return; -+ var packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1); -+ getHandle().connection.send(packet); -+ } -+ -+ @Override -+ public boolean hasSeenWinScreen() { -+ return getHandle().seenCredits; -+ } -+ -+ @Override -+ public void setHasSeenWinScreen(boolean hasSeenWinScreen) { -+ getHandle().seenCredits = hasSeenWinScreen; -+ } -+ // Paper end -+ - @Override - public void setRotation(float yaw, float pitch) { - // Paper start - Teleport API diff --git a/patches/server/0785-Fix-force-opening-enchantment-tables.patch b/patches/server/0785-Fix-force-opening-enchantment-tables.patch new file mode 100644 index 0000000000..6ddc05bd3f --- /dev/null +++ b/patches/server/0785-Fix-force-opening-enchantment-tables.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 26 Jan 2023 16:19:26 -0800 +Subject: [PATCH] Fix force-opening enchantment tables + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index df9d02eb1ffc3cc669e835e2c08d951283871db3..04fe27a84eb240f8e9bb0ed5b21fd60cfed619ad 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -411,7 +411,18 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + + // If there isn't an enchant table we can force create one, won't be very useful though. + BlockPos pos = CraftLocation.toBlockPosition(location); +- this.getHandle().openMenu(Blocks.ENCHANTING_TABLE.defaultBlockState().getMenuProvider(this.getHandle().level(), pos)); ++ // Paper start ++ MenuProvider menuProvider = Blocks.ENCHANTING_TABLE.defaultBlockState().getMenuProvider(this.getHandle().level(), pos); ++ if (menuProvider == null) { ++ if (!force) { ++ return null; ++ } ++ menuProvider = new net.minecraft.world.SimpleMenuProvider((syncId, inventory, player) -> { ++ return new net.minecraft.world.inventory.EnchantmentMenu(syncId, inventory, net.minecraft.world.inventory.ContainerLevelAccess.create(this.getHandle().level(), pos)); ++ }, Component.translatable("container.enchant")); ++ } ++ this.getHandle().openMenu(menuProvider); ++ // Paper end + + if (force) { + this.getHandle().containerMenu.checkReachable = false; diff --git a/patches/server/0785-Remove-CraftItemStack-setAmount-null-assignment.patch b/patches/server/0785-Remove-CraftItemStack-setAmount-null-assignment.patch deleted file mode 100644 index aa0acd564f..0000000000 --- a/patches/server/0785-Remove-CraftItemStack-setAmount-null-assignment.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Josh Roy -Date: Mon, 23 Jan 2023 19:19:01 -0500 -Subject: [PATCH] Remove CraftItemStack#setAmount null assignment - -This creates a problem with Paper's item serialization -api where deserialized items, which are internally -created as a CraftItemStack, will be completely lost if -#setAmount(0) is invoked (since the underlying handle -is set to null), while a regular Bukkit ItemStack -simply sets the amount field to zero, retaining the -item's data. - -Vanilla treats items with zero amounts the same as items -with less than zero amounts, so this code doesn't create -a problem with operations on the vanilla ItemStack. - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 502be683e8b04a9966043c9bee9d9fe793b12ef5..134db8c2dd72d0651fc889cc8931e7c971f62deb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -198,7 +198,7 @@ public final class CraftItemStack extends ItemStack { - } - - this.handle.setCount(amount); -- if (amount == 0) { -+ if (false && amount == 0) { // Paper - remove CraftItemStack#setAmount null assignment - this.handle = null; - } - } diff --git a/patches/server/0786-Add-Entity-Body-Yaw-API.patch b/patches/server/0786-Add-Entity-Body-Yaw-API.patch new file mode 100644 index 0000000000..2a926f1388 --- /dev/null +++ b/patches/server/0786-Add-Entity-Body-Yaw-API.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TheTuso +Date: Thu, 2 Feb 2023 16:40:41 +0100 +Subject: [PATCH] Add Entity Body Yaw API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 8a715159917950091e8efd48eaca6a54488fb896..4209434ff066670000dadb0c59fea297f03300f4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1184,6 +1184,33 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + // Paper end - entity powdered snow API + ++ // Paper start - entity body yaw API ++ @Override ++ public double getX() { ++ return this.entity.getX(); ++ } ++ ++ @Override ++ public double getY() { ++ return this.entity.getY(); ++ } ++ ++ @Override ++ public double getZ() { ++ return this.entity.getZ(); ++ } ++ ++ @Override ++ public float getPitch() { ++ return this.entity.getXRot(); ++ } ++ ++ @Override ++ public float getYaw() { ++ return this.entity.getBukkitYaw(); ++ } ++ // Paper end - entity body yaw API ++ + // Paper start - missing entity api + @Override + public boolean isInvisible() { // Paper - moved up from LivingEntity +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 2fd4a3068d86a37cc18c9203448823c53d590ffb..203e06fdff824ba67dce0e026f7ea5b746d7f258 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1211,4 +1211,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + this.getHandle().frictionState = state; + } + // Paper end - friction API ++ ++ // Paper start - body yaw API ++ @Override ++ public float getBodyYaw() { ++ return this.getHandle().getVisualRotationYInDegrees(); ++ } ++ ++ @Override ++ public void setBodyYaw(final float bodyYaw) { ++ this.getHandle().setYBodyRot(bodyYaw); ++ } ++ // Paper end - body yaw API + } diff --git a/patches/server/0786-Fix-force-opening-enchantment-tables.patch b/patches/server/0786-Fix-force-opening-enchantment-tables.patch deleted file mode 100644 index 6ddc05bd3f..0000000000 --- a/patches/server/0786-Fix-force-opening-enchantment-tables.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 26 Jan 2023 16:19:26 -0800 -Subject: [PATCH] Fix force-opening enchantment tables - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index df9d02eb1ffc3cc669e835e2c08d951283871db3..04fe27a84eb240f8e9bb0ed5b21fd60cfed619ad 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -411,7 +411,18 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - - // If there isn't an enchant table we can force create one, won't be very useful though. - BlockPos pos = CraftLocation.toBlockPosition(location); -- this.getHandle().openMenu(Blocks.ENCHANTING_TABLE.defaultBlockState().getMenuProvider(this.getHandle().level(), pos)); -+ // Paper start -+ MenuProvider menuProvider = Blocks.ENCHANTING_TABLE.defaultBlockState().getMenuProvider(this.getHandle().level(), pos); -+ if (menuProvider == null) { -+ if (!force) { -+ return null; -+ } -+ menuProvider = new net.minecraft.world.SimpleMenuProvider((syncId, inventory, player) -> { -+ return new net.minecraft.world.inventory.EnchantmentMenu(syncId, inventory, net.minecraft.world.inventory.ContainerLevelAccess.create(this.getHandle().level(), pos)); -+ }, Component.translatable("container.enchant")); -+ } -+ this.getHandle().openMenu(menuProvider); -+ // Paper end - - if (force) { - this.getHandle().containerMenu.checkReachable = false; diff --git a/patches/server/0787-Add-Entity-Body-Yaw-API.patch b/patches/server/0787-Add-Entity-Body-Yaw-API.patch deleted file mode 100644 index 2a926f1388..0000000000 --- a/patches/server/0787-Add-Entity-Body-Yaw-API.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TheTuso -Date: Thu, 2 Feb 2023 16:40:41 +0100 -Subject: [PATCH] Add Entity Body Yaw API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 8a715159917950091e8efd48eaca6a54488fb896..4209434ff066670000dadb0c59fea297f03300f4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1184,6 +1184,33 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - } - // Paper end - entity powdered snow API - -+ // Paper start - entity body yaw API -+ @Override -+ public double getX() { -+ return this.entity.getX(); -+ } -+ -+ @Override -+ public double getY() { -+ return this.entity.getY(); -+ } -+ -+ @Override -+ public double getZ() { -+ return this.entity.getZ(); -+ } -+ -+ @Override -+ public float getPitch() { -+ return this.entity.getXRot(); -+ } -+ -+ @Override -+ public float getYaw() { -+ return this.entity.getBukkitYaw(); -+ } -+ // Paper end - entity body yaw API -+ - // Paper start - missing entity api - @Override - public boolean isInvisible() { // Paper - moved up from LivingEntity -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 2fd4a3068d86a37cc18c9203448823c53d590ffb..203e06fdff824ba67dce0e026f7ea5b746d7f258 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1211,4 +1211,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - this.getHandle().frictionState = state; - } - // Paper end - friction API -+ -+ // Paper start - body yaw API -+ @Override -+ public float getBodyYaw() { -+ return this.getHandle().getVisualRotationYInDegrees(); -+ } -+ -+ @Override -+ public void setBodyYaw(final float bodyYaw) { -+ this.getHandle().setYBodyRot(bodyYaw); -+ } -+ // Paper end - body yaw API - } diff --git a/patches/server/0787-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch b/patches/server/0787-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch new file mode 100644 index 0000000000..9c1f7e2d47 --- /dev/null +++ b/patches/server/0787-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Mon, 27 Feb 2023 19:16:07 +0100 +Subject: [PATCH] Fix MC-157464 Prevent sleeping villagers moving towards food + +Fixes sleeping villagers moving to nearby food by adding an !isSleeping predicate + +Relevant links: +https://bugs.mojang.com/browse/MC-157464 +https://github.com/PaperMC/Paper/issues/8569 + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java +index 1c5cec4e3dbf2daf9e06d8d7dfb30b3f7744a1f5..bb65d46967cb04f611b3c9c97d5732cfb21ede9b 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java +@@ -38,7 +38,7 @@ public class VillagerGoalPackages { + Pair.of(1, new MoveToTargetSink()), + Pair.of(2, PoiCompetitorScan.create()), + Pair.of(3, new LookAndFollowTradingPlayerSink(speed)), +- Pair.of(5, GoToWantedItem.create(speed, false, 4)), ++ Pair.of(5, GoToWantedItem.create(villager -> !villager.isSleeping(), speed, false, 4)), // Paper - Fix MC-157464 + Pair.of( + 6, AcquirePoi.create(profession.acquirableJobSite(), MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, true, Optional.empty()) + ), diff --git a/patches/server/0788-Add-EntityFertilizeEggEvent.patch b/patches/server/0788-Add-EntityFertilizeEggEvent.patch new file mode 100644 index 0000000000..ea7e33d8b0 --- /dev/null +++ b/patches/server/0788-Add-EntityFertilizeEggEvent.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Fri, 24 Jun 2022 12:39:34 +0200 +Subject: [PATCH] Add EntityFertilizeEggEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java +index ed7f5eb9b3b700c2f817d61ee0bf8a6952731510..9a9ecc3e2c176c6d9700c4c585250b9780b7629b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java +@@ -448,6 +448,10 @@ public class Turtle extends Animal { + if (entityplayer == null && this.partner.getLoveCause() != null) { + entityplayer = this.partner.getLoveCause(); + } ++ // Paper start - Add EntityFertilizeEggEvent event ++ io.papermc.paper.event.entity.EntityFertilizeEggEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this.animal, this.partner); ++ if (event.isCancelled()) return; ++ // Paper end - Add EntityFertilizeEggEvent event + + if (entityplayer != null) { + entityplayer.awardStat(Stats.ANIMALS_BRED); +@@ -462,7 +466,7 @@ public class Turtle extends Animal { + RandomSource randomsource = this.animal.getRandom(); + + if (getServerLevel((Level) this.level).getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { +- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper; ++ if (event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper - Add EntityFertilizeEggEvent event + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +index 100be2ed533450eda32d9c4eb9eb1067846d1516..36846ba6b6c7494c745ebd8b221479a9d02ff318 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java ++++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +@@ -270,7 +270,12 @@ public class Frog extends Animal implements VariantHolder> { + + @Override + public void spawnChildFromBreeding(ServerLevel world, Animal other) { +- this.finalizeSpawnChildFromBreeding(world, other, null); ++ // Paper start - Add EntityFertilizeEggEvent event ++ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other); ++ if (result.isCancelled()) return; ++ ++ this.finalizeSpawnChildFromBreeding(world, other, null, result.getExperience()); // Paper - use craftbukkit call that takes experience amount ++ // Paper end - Add EntityFertilizeEggEvent event + this.getBrain().setMemory(MemoryModuleType.IS_PREGNANT, Unit.INSTANCE); + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java +index 014e1ea1603bc7a7b42ae7ff7d12e5a41f331d2f..af2f6e690fc51d319b77d081466c2dc7a1d8fe19 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java ++++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java +@@ -340,11 +340,16 @@ public class Sniffer extends Animal { + + @Override + public void spawnChildFromBreeding(ServerLevel world, Animal other) { ++ // Paper start - Add EntityFertilizeEggEvent event ++ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other); ++ if (result.isCancelled()) return; ++ // Paper end - Add EntityFertilizeEggEvent event ++ + ItemStack itemstack = new ItemStack(Items.SNIFFER_EGG); + ItemEntity entityitem = new ItemEntity(world, this.position().x(), this.position().y(), this.position().z(), itemstack); + + entityitem.setDefaultPickUpDelay(); +- this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null); ++ this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null, result.getExperience()); // Paper - Add EntityFertilizeEggEvent event + if (this.spawnAtLocation(world, entityitem) != null) { // Paper - Call EntityDropItemEvent + this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F); + } // Paper - Call EntityDropItemEvent +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index ea0241de1a7ef64059cddcb43c41f56b91901897..d63b9c666cf6eb1de114c5c89867b8d233267c9e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -2195,4 +2195,28 @@ public class CraftEventFactory { + return event.callEvent(); + } + // Paper end ++ ++ // Paper start - add EntityFertilizeEggEvent ++ /** ++ * Calls the {@link io.papermc.paper.event.entity.EntityFertilizeEggEvent}. ++ * If the event is cancelled, this method also resets the love on both the {@code breeding} and {@code other} entity. ++ * ++ * @param breeding the entity on which #spawnChildFromBreeding was called. ++ * @param other the partner of the entity. ++ * @return the event after it was called. The instance may be used to retrieve the experience of the event. ++ */ ++ public static io.papermc.paper.event.entity.EntityFertilizeEggEvent callEntityFertilizeEggEvent(Animal breeding, Animal other) { ++ ServerPlayer serverPlayer = breeding.getLoveCause(); ++ if (serverPlayer == null) serverPlayer = other.getLoveCause(); ++ final int experience = breeding.getRandom().nextInt(7) + 1; // From Animal#spawnChildFromBreeding(ServerLevel, Animal) ++ ++ final io.papermc.paper.event.entity.EntityFertilizeEggEvent event = new io.papermc.paper.event.entity.EntityFertilizeEggEvent((LivingEntity) breeding.getBukkitEntity(), (LivingEntity) other.getBukkitEntity(), serverPlayer == null ? null : serverPlayer.getBukkitEntity(), breeding.breedItem == null ? null : CraftItemStack.asCraftMirror(breeding.breedItem).clone(), experience); ++ if (!event.callEvent()) { ++ breeding.resetLove(); ++ other.resetLove(); // stop the pathfinding to avoid infinite loop ++ } ++ ++ return event; ++ } ++ // Paper end - add EntityFertilizeEggEvent + } diff --git a/patches/server/0788-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch b/patches/server/0788-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch deleted file mode 100644 index 9c1f7e2d47..0000000000 --- a/patches/server/0788-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Mon, 27 Feb 2023 19:16:07 +0100 -Subject: [PATCH] Fix MC-157464 Prevent sleeping villagers moving towards food - -Fixes sleeping villagers moving to nearby food by adding an !isSleeping predicate - -Relevant links: -https://bugs.mojang.com/browse/MC-157464 -https://github.com/PaperMC/Paper/issues/8569 - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -index 1c5cec4e3dbf2daf9e06d8d7dfb30b3f7744a1f5..bb65d46967cb04f611b3c9c97d5732cfb21ede9b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -@@ -38,7 +38,7 @@ public class VillagerGoalPackages { - Pair.of(1, new MoveToTargetSink()), - Pair.of(2, PoiCompetitorScan.create()), - Pair.of(3, new LookAndFollowTradingPlayerSink(speed)), -- Pair.of(5, GoToWantedItem.create(speed, false, 4)), -+ Pair.of(5, GoToWantedItem.create(villager -> !villager.isSleeping(), speed, false, 4)), // Paper - Fix MC-157464 - Pair.of( - 6, AcquirePoi.create(profession.acquirableJobSite(), MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, true, Optional.empty()) - ), diff --git a/patches/server/0789-Add-EntityFertilizeEggEvent.patch b/patches/server/0789-Add-EntityFertilizeEggEvent.patch deleted file mode 100644 index ea7e33d8b0..0000000000 --- a/patches/server/0789-Add-EntityFertilizeEggEvent.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Fri, 24 Jun 2022 12:39:34 +0200 -Subject: [PATCH] Add EntityFertilizeEggEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index ed7f5eb9b3b700c2f817d61ee0bf8a6952731510..9a9ecc3e2c176c6d9700c4c585250b9780b7629b 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -448,6 +448,10 @@ public class Turtle extends Animal { - if (entityplayer == null && this.partner.getLoveCause() != null) { - entityplayer = this.partner.getLoveCause(); - } -+ // Paper start - Add EntityFertilizeEggEvent event -+ io.papermc.paper.event.entity.EntityFertilizeEggEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this.animal, this.partner); -+ if (event.isCancelled()) return; -+ // Paper end - Add EntityFertilizeEggEvent event - - if (entityplayer != null) { - entityplayer.awardStat(Stats.ANIMALS_BRED); -@@ -462,7 +466,7 @@ public class Turtle extends Animal { - RandomSource randomsource = this.animal.getRandom(); - - if (getServerLevel((Level) this.level).getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { -- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper; -+ if (event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper - Add EntityFertilizeEggEvent event - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index 100be2ed533450eda32d9c4eb9eb1067846d1516..36846ba6b6c7494c745ebd8b221479a9d02ff318 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -@@ -270,7 +270,12 @@ public class Frog extends Animal implements VariantHolder> { - - @Override - public void spawnChildFromBreeding(ServerLevel world, Animal other) { -- this.finalizeSpawnChildFromBreeding(world, other, null); -+ // Paper start - Add EntityFertilizeEggEvent event -+ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other); -+ if (result.isCancelled()) return; -+ -+ this.finalizeSpawnChildFromBreeding(world, other, null, result.getExperience()); // Paper - use craftbukkit call that takes experience amount -+ // Paper end - Add EntityFertilizeEggEvent event - this.getBrain().setMemory(MemoryModuleType.IS_PREGNANT, Unit.INSTANCE); - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -index 014e1ea1603bc7a7b42ae7ff7d12e5a41f331d2f..af2f6e690fc51d319b77d081466c2dc7a1d8fe19 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -+++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -@@ -340,11 +340,16 @@ public class Sniffer extends Animal { - - @Override - public void spawnChildFromBreeding(ServerLevel world, Animal other) { -+ // Paper start - Add EntityFertilizeEggEvent event -+ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other); -+ if (result.isCancelled()) return; -+ // Paper end - Add EntityFertilizeEggEvent event -+ - ItemStack itemstack = new ItemStack(Items.SNIFFER_EGG); - ItemEntity entityitem = new ItemEntity(world, this.position().x(), this.position().y(), this.position().z(), itemstack); - - entityitem.setDefaultPickUpDelay(); -- this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null); -+ this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null, result.getExperience()); // Paper - Add EntityFertilizeEggEvent event - if (this.spawnAtLocation(world, entityitem) != null) { // Paper - Call EntityDropItemEvent - this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F); - } // Paper - Call EntityDropItemEvent -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index ea0241de1a7ef64059cddcb43c41f56b91901897..d63b9c666cf6eb1de114c5c89867b8d233267c9e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -2195,4 +2195,28 @@ public class CraftEventFactory { - return event.callEvent(); - } - // Paper end -+ -+ // Paper start - add EntityFertilizeEggEvent -+ /** -+ * Calls the {@link io.papermc.paper.event.entity.EntityFertilizeEggEvent}. -+ * If the event is cancelled, this method also resets the love on both the {@code breeding} and {@code other} entity. -+ * -+ * @param breeding the entity on which #spawnChildFromBreeding was called. -+ * @param other the partner of the entity. -+ * @return the event after it was called. The instance may be used to retrieve the experience of the event. -+ */ -+ public static io.papermc.paper.event.entity.EntityFertilizeEggEvent callEntityFertilizeEggEvent(Animal breeding, Animal other) { -+ ServerPlayer serverPlayer = breeding.getLoveCause(); -+ if (serverPlayer == null) serverPlayer = other.getLoveCause(); -+ final int experience = breeding.getRandom().nextInt(7) + 1; // From Animal#spawnChildFromBreeding(ServerLevel, Animal) -+ -+ final io.papermc.paper.event.entity.EntityFertilizeEggEvent event = new io.papermc.paper.event.entity.EntityFertilizeEggEvent((LivingEntity) breeding.getBukkitEntity(), (LivingEntity) other.getBukkitEntity(), serverPlayer == null ? null : serverPlayer.getBukkitEntity(), breeding.breedItem == null ? null : CraftItemStack.asCraftMirror(breeding.breedItem).clone(), experience); -+ if (!event.callEvent()) { -+ breeding.resetLove(); -+ other.resetLove(); // stop the pathfinding to avoid infinite loop -+ } -+ -+ return event; -+ } -+ // Paper end - add EntityFertilizeEggEvent - } diff --git a/patches/server/0789-Fix-HumanEntity-drop-not-updating-the-client-inv.patch b/patches/server/0789-Fix-HumanEntity-drop-not-updating-the-client-inv.patch new file mode 100644 index 0000000000..21d4d0ad65 --- /dev/null +++ b/patches/server/0789-Fix-HumanEntity-drop-not-updating-the-client-inv.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 10 Oct 2021 18:18:01 -0700 +Subject: [PATCH] Fix HumanEntity#drop not updating the client inv + +== AT == +public net.minecraft.server.level.ServerPlayer containerSynchronizer + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index 04fe27a84eb240f8e9bb0ed5b21fd60cfed619ad..7dddf4dd090fcd9e86b147d7e4ddeaa99800713e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -782,8 +782,15 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + // Paper end + @Override + public boolean dropItem(boolean dropAll) { +- if (!(this.getHandle() instanceof ServerPlayer)) return false; +- return ((ServerPlayer) this.getHandle()).drop(dropAll); ++ // Paper start - Fix HumanEntity#drop not updating the client inv ++ if (!(this.getHandle() instanceof ServerPlayer player)) return false; ++ boolean success = player.drop(dropAll); ++ if (!success) return false; ++ final net.minecraft.world.entity.player.Inventory inv = player.getInventory(); ++ final java.util.OptionalInt optionalSlot = player.containerMenu.findSlot(inv, inv.selected); ++ optionalSlot.ifPresent(slot -> player.containerSynchronizer.sendSlotChange(player.containerMenu, slot, inv.getSelected())); ++ return true; ++ // Paper end - Fix HumanEntity#drop not updating the client inv + } + + @Override diff --git a/patches/server/0790-Add-CompostItemEvent-and-EntityCompostItemEvent.patch b/patches/server/0790-Add-CompostItemEvent-and-EntityCompostItemEvent.patch new file mode 100644 index 0000000000..2e105236ee --- /dev/null +++ b/patches/server/0790-Add-CompostItemEvent-and-EntityCompostItemEvent.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Sun, 8 Aug 2021 19:56:02 +0200 +Subject: [PATCH] Add CompostItemEvent and EntityCompostItemEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +index 05b2eab26e2dc8e143e9fff2dcec40cfe927a197..db837b250fc35af5b528bf973b3b07f63e79bc46 100644 +--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +@@ -340,7 +340,21 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + int i = (Integer) iblockdata.getValue(ComposterBlock.LEVEL); + float f = ComposterBlock.COMPOSTABLES.getFloat(itemstack.getItem()); + +- if ((i != 0 || f <= 0.0F) && rand >= (double) f) { ++ // Paper start - Add CompostItemEvent and EntityCompostItemEvent ++ boolean willRaiseLevel = !((i != 0 || f <= 0.0F) && rand >= (double) f); ++ final io.papermc.paper.event.block.CompostItemEvent event; ++ if (entity == null) { ++ event = new io.papermc.paper.event.block.CompostItemEvent(org.bukkit.craftbukkit.block.CraftBlock.at(generatoraccess, blockposition), itemstack.getBukkitStack(), willRaiseLevel); ++ } else { ++ event = new io.papermc.paper.event.entity.EntityCompostItemEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(generatoraccess, blockposition), itemstack.getBukkitStack(), willRaiseLevel); ++ } ++ if (!event.callEvent()) { // check for cancellation of entity event (non entity event can't be cancelled cause of hoppers) ++ return null; ++ } ++ willRaiseLevel = event.willRaiseLevel(); ++ ++ if (!willRaiseLevel) { ++ // Paper end - Add CompostItemEvent and EntityCompostItemEvent + return iblockdata; + } else { + int j = i + 1; +@@ -489,6 +503,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + if (!itemstack.isEmpty()) { + this.changed = true; + BlockState iblockdata = ComposterBlock.addItem((Entity) null, this.state, this.level, this.pos, itemstack); ++ // Paper start - Add CompostItemEvent and EntityCompostItemEvent ++ if (iblockdata == null) { ++ return; ++ } ++ // Paper end - Add CompostItemEvent and EntityCompostItemEvent + + this.level.levelEvent(1500, this.pos, iblockdata != this.state ? 1 : 0); + this.removeItemNoUpdate(0); diff --git a/patches/server/0790-Fix-HumanEntity-drop-not-updating-the-client-inv.patch b/patches/server/0790-Fix-HumanEntity-drop-not-updating-the-client-inv.patch deleted file mode 100644 index 21d4d0ad65..0000000000 --- a/patches/server/0790-Fix-HumanEntity-drop-not-updating-the-client-inv.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 10 Oct 2021 18:18:01 -0700 -Subject: [PATCH] Fix HumanEntity#drop not updating the client inv - -== AT == -public net.minecraft.server.level.ServerPlayer containerSynchronizer - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 04fe27a84eb240f8e9bb0ed5b21fd60cfed619ad..7dddf4dd090fcd9e86b147d7e4ddeaa99800713e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -782,8 +782,15 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - // Paper end - @Override - public boolean dropItem(boolean dropAll) { -- if (!(this.getHandle() instanceof ServerPlayer)) return false; -- return ((ServerPlayer) this.getHandle()).drop(dropAll); -+ // Paper start - Fix HumanEntity#drop not updating the client inv -+ if (!(this.getHandle() instanceof ServerPlayer player)) return false; -+ boolean success = player.drop(dropAll); -+ if (!success) return false; -+ final net.minecraft.world.entity.player.Inventory inv = player.getInventory(); -+ final java.util.OptionalInt optionalSlot = player.containerMenu.findSlot(inv, inv.selected); -+ optionalSlot.ifPresent(slot -> player.containerSynchronizer.sendSlotChange(player.containerMenu, slot, inv.getSelected())); -+ return true; -+ // Paper end - Fix HumanEntity#drop not updating the client inv - } - - @Override diff --git a/patches/server/0791-Add-CompostItemEvent-and-EntityCompostItemEvent.patch b/patches/server/0791-Add-CompostItemEvent-and-EntityCompostItemEvent.patch deleted file mode 100644 index 2e105236ee..0000000000 --- a/patches/server/0791-Add-CompostItemEvent-and-EntityCompostItemEvent.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Sun, 8 Aug 2021 19:56:02 +0200 -Subject: [PATCH] Add CompostItemEvent and EntityCompostItemEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -index 05b2eab26e2dc8e143e9fff2dcec40cfe927a197..db837b250fc35af5b528bf973b3b07f63e79bc46 100644 ---- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -@@ -340,7 +340,21 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - int i = (Integer) iblockdata.getValue(ComposterBlock.LEVEL); - float f = ComposterBlock.COMPOSTABLES.getFloat(itemstack.getItem()); - -- if ((i != 0 || f <= 0.0F) && rand >= (double) f) { -+ // Paper start - Add CompostItemEvent and EntityCompostItemEvent -+ boolean willRaiseLevel = !((i != 0 || f <= 0.0F) && rand >= (double) f); -+ final io.papermc.paper.event.block.CompostItemEvent event; -+ if (entity == null) { -+ event = new io.papermc.paper.event.block.CompostItemEvent(org.bukkit.craftbukkit.block.CraftBlock.at(generatoraccess, blockposition), itemstack.getBukkitStack(), willRaiseLevel); -+ } else { -+ event = new io.papermc.paper.event.entity.EntityCompostItemEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(generatoraccess, blockposition), itemstack.getBukkitStack(), willRaiseLevel); -+ } -+ if (!event.callEvent()) { // check for cancellation of entity event (non entity event can't be cancelled cause of hoppers) -+ return null; -+ } -+ willRaiseLevel = event.willRaiseLevel(); -+ -+ if (!willRaiseLevel) { -+ // Paper end - Add CompostItemEvent and EntityCompostItemEvent - return iblockdata; - } else { - int j = i + 1; -@@ -489,6 +503,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - if (!itemstack.isEmpty()) { - this.changed = true; - BlockState iblockdata = ComposterBlock.addItem((Entity) null, this.state, this.level, this.pos, itemstack); -+ // Paper start - Add CompostItemEvent and EntityCompostItemEvent -+ if (iblockdata == null) { -+ return; -+ } -+ // Paper end - Add CompostItemEvent and EntityCompostItemEvent - - this.level.levelEvent(1500, this.pos, iblockdata != this.state ? 1 : 0); - this.removeItemNoUpdate(0); diff --git a/patches/server/0791-Correctly-handle-ArmorStand-invisibility.patch b/patches/server/0791-Correctly-handle-ArmorStand-invisibility.patch new file mode 100644 index 0000000000..4c4c5048be --- /dev/null +++ b/patches/server/0791-Correctly-handle-ArmorStand-invisibility.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 5 Mar 2023 14:38:21 -0800 +Subject: [PATCH] Correctly handle ArmorStand invisibility + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java +index c8713200d946b0fdd74b60d0c2c136c8226389e0..184fe8257e5ffb0ef090ffa2833786a4db8b59ea 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java +@@ -152,6 +152,14 @@ public class CraftArmorStand extends CraftLivingEntity implements ArmorStand { + this.getHandle().noPhysics = !gravity; + } + ++ // Paper start - Armor Stand has its own invisible field ++ @Override ++ public void setInvisible(final boolean invisible) { ++ this.getHandle().setInvisible(invisible); ++ super.setInvisible(invisible); ++ } ++ // Paper end ++ + @Override + public boolean isVisible() { + return !this.getHandle().isInvisible(); diff --git a/patches/server/0792-Correctly-handle-ArmorStand-invisibility.patch b/patches/server/0792-Correctly-handle-ArmorStand-invisibility.patch deleted file mode 100644 index 4c4c5048be..0000000000 --- a/patches/server/0792-Correctly-handle-ArmorStand-invisibility.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 5 Mar 2023 14:38:21 -0800 -Subject: [PATCH] Correctly handle ArmorStand invisibility - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java -index c8713200d946b0fdd74b60d0c2c136c8226389e0..184fe8257e5ffb0ef090ffa2833786a4db8b59ea 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java -@@ -152,6 +152,14 @@ public class CraftArmorStand extends CraftLivingEntity implements ArmorStand { - this.getHandle().noPhysics = !gravity; - } - -+ // Paper start - Armor Stand has its own invisible field -+ @Override -+ public void setInvisible(final boolean invisible) { -+ this.getHandle().setInvisible(invisible); -+ super.setInvisible(invisible); -+ } -+ // Paper end -+ - @Override - public boolean isVisible() { - return !this.getHandle().isInvisible(); diff --git a/patches/server/0792-Fix-advancement-triggers-for-entity-damage.patch b/patches/server/0792-Fix-advancement-triggers-for-entity-damage.patch new file mode 100644 index 0000000000..c7075265f1 --- /dev/null +++ b/patches/server/0792-Fix-advancement-triggers-for-entity-damage.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 16 Mar 2023 10:04:17 +0100 +Subject: [PATCH] Fix advancement triggers for entity damage + +Changes the Interaction entity's trigger to use the vanilla +generic damage source + +Fixes a couple places where the original damage and modified damage +were passed in the reverse order to the advancement triggers + +diff --git a/src/main/java/net/minecraft/world/entity/Interaction.java b/src/main/java/net/minecraft/world/entity/Interaction.java +index 821bb93e1b055ba38fafe3b7079d79aa062ebe8a..221d73676fe2fd240a47cf312c1179e049298cac 100644 +--- a/src/main/java/net/minecraft/world/entity/Interaction.java ++++ b/src/main/java/net/minecraft/world/entity/Interaction.java +@@ -159,7 +159,7 @@ public class Interaction extends Entity implements Attackable, Targeting { + // CraftBukkit end + this.attack = new Interaction.PlayerAction(entityhuman.getUUID(), this.level().getGameTime()); + if (entityhuman instanceof ServerPlayer entityplayer) { +- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, source, (float) event.getFinalDamage(), 1.0F, false); // CraftBukkit ++ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, entityhuman.damageSources().generic(), 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit // Paper - use correct source and fix taken/dealt param order + } + + return !this.getResponse(); +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 9ef5c617cb05f08758105772b9124f6c318b5c17..24245cfb160dc990b3661388c2f95b9383f98428 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2463,7 +2463,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + // Duplicate triggers if blocking + if (event.getDamage(DamageModifier.BLOCKING) < 0) { + if (this instanceof ServerPlayer) { +- CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, f, originalDamage, true); ++ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, originalDamage, f, true); // Paper - fix taken/dealt param order + f2 = (float) -event.getDamage(DamageModifier.BLOCKING); + if (f2 > 0.0F && f2 < 3.4028235E37F) { + ((ServerPlayer) this).awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(originalDamage * 10.0F)); +@@ -2471,7 +2471,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + if (damagesource.getEntity() instanceof ServerPlayer) { +- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damagesource.getEntity(), this, damagesource, f, originalDamage, true); ++ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damagesource.getEntity(), this, damagesource, originalDamage, f, true); // Paper - fix taken/dealt param order + } + + return true; diff --git a/patches/server/0793-Fix-advancement-triggers-for-entity-damage.patch b/patches/server/0793-Fix-advancement-triggers-for-entity-damage.patch deleted file mode 100644 index d85577a078..0000000000 --- a/patches/server/0793-Fix-advancement-triggers-for-entity-damage.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 16 Mar 2023 10:04:17 +0100 -Subject: [PATCH] Fix advancement triggers for entity damage - -Changes the Interaction entity's trigger to use the vanilla -generic damage source - -Fixes a couple places where the original damage and modified damage -were passed in the reverse order to the advancement triggers - -diff --git a/src/main/java/net/minecraft/world/entity/Interaction.java b/src/main/java/net/minecraft/world/entity/Interaction.java -index 821bb93e1b055ba38fafe3b7079d79aa062ebe8a..221d73676fe2fd240a47cf312c1179e049298cac 100644 ---- a/src/main/java/net/minecraft/world/entity/Interaction.java -+++ b/src/main/java/net/minecraft/world/entity/Interaction.java -@@ -159,7 +159,7 @@ public class Interaction extends Entity implements Attackable, Targeting { - // CraftBukkit end - this.attack = new Interaction.PlayerAction(entityhuman.getUUID(), this.level().getGameTime()); - if (entityhuman instanceof ServerPlayer entityplayer) { -- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, source, (float) event.getFinalDamage(), 1.0F, false); // CraftBukkit -+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, entityhuman.damageSources().generic(), 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit // Paper - use correct source and fix taken/dealt param order - } - - return !this.getResponse(); -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index da42691504177e1e2614db777cbe346f73725eda..a4d24269c1365f32f232116f1530ac75b096c6ab 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2465,7 +2465,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - // Duplicate triggers if blocking - if (event.getDamage(DamageModifier.BLOCKING) < 0) { - if (this instanceof ServerPlayer) { -- CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, f, originalDamage, true); -+ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, originalDamage, f, true); // Paper - fix taken/dealt param order - f2 = (float) -event.getDamage(DamageModifier.BLOCKING); - if (f2 > 0.0F && f2 < 3.4028235E37F) { - ((ServerPlayer) this).awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(originalDamage * 10.0F)); -@@ -2473,7 +2473,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - if (damagesource.getEntity() instanceof ServerPlayer) { -- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damagesource.getEntity(), this, damagesource, f, originalDamage, true); -+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damagesource.getEntity(), this, damagesource, originalDamage, f, true); // Paper - fix taken/dealt param order - } - - return true; diff --git a/patches/server/0793-Fix-text-display-error-on-spawn.patch b/patches/server/0793-Fix-text-display-error-on-spawn.patch new file mode 100644 index 0000000000..d783ac8eee --- /dev/null +++ b/patches/server/0793-Fix-text-display-error-on-spawn.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 16 Mar 2023 16:27:50 +0100 +Subject: [PATCH] Fix text display error on spawn + + +diff --git a/src/main/java/net/minecraft/world/entity/Display.java b/src/main/java/net/minecraft/world/entity/Display.java +index d7d940e6b397e52cb7d78bc6f5fc26e8096f9228..e6cbf4506c75046a89fad778e138b448fb4a29a9 100644 +--- a/src/main/java/net/minecraft/world/entity/Display.java ++++ b/src/main/java/net/minecraft/world/entity/Display.java +@@ -903,7 +903,7 @@ public abstract class Display extends Entity { + b = loadFlag(b, nbt, "default_background", (byte)4); + Optional optional = Display.TextDisplay.Align.CODEC + .decode(NbtOps.INSTANCE, nbt.get("alignment")) +- .resultOrPartial(Util.prefix("Display entity", Display.LOGGER::error)) ++ .result() // Paper - Hide text display error on spawn + .map(Pair::getFirst); + if (optional.isPresent()) { + b = switch ((Display.TextDisplay.Align)optional.get()) { diff --git a/patches/server/0794-Fix-inventories-returning-null-Locations.patch b/patches/server/0794-Fix-inventories-returning-null-Locations.patch new file mode 100644 index 0000000000..1a65689fad --- /dev/null +++ b/patches/server/0794-Fix-inventories-returning-null-Locations.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 15 Mar 2023 18:29:45 -0700 +Subject: [PATCH] Fix inventories returning null Locations + +Wandering Trader, AbstractHorse, Beacon and Composter inventories returned null locations +when a block or entity location is readily available + +Co-authored-by: Lukas Planz + +diff --git a/src/main/java/net/minecraft/world/SimpleContainer.java b/src/main/java/net/minecraft/world/SimpleContainer.java +index 13a32ef8f86b678dcce83c41c78b47d9aab9f16b..b0963c534afe5be164701cb283f1849e32ae5a86 100644 +--- a/src/main/java/net/minecraft/world/SimpleContainer.java ++++ b/src/main/java/net/minecraft/world/SimpleContainer.java +@@ -63,6 +63,16 @@ public class SimpleContainer implements Container, StackedContentsCompatible { + + @Override + public Location getLocation() { ++ // Paper start - Fix inventories returning null Locations ++ // When the block inventory does not have a tile state that implements getLocation, e. g. composters ++ if (this.bukkitOwner instanceof org.bukkit.inventory.BlockInventoryHolder blockInventoryHolder) { ++ return blockInventoryHolder.getBlock().getLocation(); ++ } ++ // When the bukkit owner is a bukkit entity, but does not implement Container itself, e. g. horses ++ if (this.bukkitOwner instanceof org.bukkit.entity.Entity entity) { ++ return entity.getLocation(); ++ } ++ // Paper end - Fix inventories returning null Locations + return null; + } + +diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +index 9db647cfbd3f9c884465cf3d3a1b911d46a3da58..c0dfa04511110be366ee5b0bd75efc51afcce2e4 100644 +--- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +@@ -52,6 +52,12 @@ public class BeaconMenu extends AbstractContainerMenu { + public int getMaxStackSize() { + return 1; + } ++ // Paper start - Fix inventories returning null Locations ++ @Override ++ public org.bukkit.Location getLocation() { ++ return context.getLocation(); ++ } ++ // Paper end - Fix inventories returning null Locations + }; + checkContainerDataCount(propertyDelegate, 3); + this.beaconData = propertyDelegate; +diff --git a/src/main/java/net/minecraft/world/inventory/MerchantContainer.java b/src/main/java/net/minecraft/world/inventory/MerchantContainer.java +index 7cc96b62f6bacdb44a37d74db214bd0e11c4d503..9140fab07aab32065f7a3b5d13dd17d61dc6d646 100644 +--- a/src/main/java/net/minecraft/world/inventory/MerchantContainer.java ++++ b/src/main/java/net/minecraft/world/inventory/MerchantContainer.java +@@ -65,7 +65,7 @@ public class MerchantContainer implements Container { + + @Override + public Location getLocation() { +- return (this.merchant instanceof Villager) ? ((Villager) this.merchant).getBukkitEntity().getLocation() : null; ++ return (this.merchant instanceof AbstractVillager) ? ((AbstractVillager) this.merchant).getBukkitEntity().getLocation() : null; // Paper - Fix inventories returning null Locations + } + // CraftBukkit end + diff --git a/patches/server/0794-Fix-text-display-error-on-spawn.patch b/patches/server/0794-Fix-text-display-error-on-spawn.patch deleted file mode 100644 index d783ac8eee..0000000000 --- a/patches/server/0794-Fix-text-display-error-on-spawn.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Thu, 16 Mar 2023 16:27:50 +0100 -Subject: [PATCH] Fix text display error on spawn - - -diff --git a/src/main/java/net/minecraft/world/entity/Display.java b/src/main/java/net/minecraft/world/entity/Display.java -index d7d940e6b397e52cb7d78bc6f5fc26e8096f9228..e6cbf4506c75046a89fad778e138b448fb4a29a9 100644 ---- a/src/main/java/net/minecraft/world/entity/Display.java -+++ b/src/main/java/net/minecraft/world/entity/Display.java -@@ -903,7 +903,7 @@ public abstract class Display extends Entity { - b = loadFlag(b, nbt, "default_background", (byte)4); - Optional optional = Display.TextDisplay.Align.CODEC - .decode(NbtOps.INSTANCE, nbt.get("alignment")) -- .resultOrPartial(Util.prefix("Display entity", Display.LOGGER::error)) -+ .result() // Paper - Hide text display error on spawn - .map(Pair::getFirst); - if (optional.isPresent()) { - b = switch ((Display.TextDisplay.Align)optional.get()) { diff --git a/patches/server/0795-Add-Shearable-API.patch b/patches/server/0795-Add-Shearable-API.patch new file mode 100644 index 0000000000..302cec90c2 --- /dev/null +++ b/patches/server/0795-Add-Shearable-API.patch @@ -0,0 +1,135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 17 Oct 2021 15:39:48 -0400 +Subject: [PATCH] Add Shearable API + + +diff --git a/src/main/java/io/papermc/paper/entity/PaperShearable.java b/src/main/java/io/papermc/paper/entity/PaperShearable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b02e2f2ea4f83615897cb4c66be8b29948097815 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/PaperShearable.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.entity; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.sound.Sound; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.entity.Shearable; ++import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.Items; ++import org.jetbrains.annotations.NotNull; ++ ++public interface PaperShearable extends io.papermc.paper.entity.Shearable { ++ ++ Shearable getHandle(); ++ ++ @Override ++ default boolean readyToBeSheared() { ++ return this.getHandle().readyForShearing(); ++ } ++ ++ @Override ++ default void shear(@NotNull Sound.Source source) { ++ if (!(this.getHandle().level() instanceof final ServerLevel serverLevel)) return; ++ this.getHandle().shear(serverLevel, PaperAdventure.asVanilla(source), new ItemStack(Items.SHEARS)); ++ } ++} +diff --git a/src/main/java/net/minecraft/world/entity/Shearable.java b/src/main/java/net/minecraft/world/entity/Shearable.java +index a3095eee48d8b87a35ad35da9c8a2a9ca20c92bc..35076593f3ccd651295ae1fc9bcf8256c19672dd 100644 +--- a/src/main/java/net/minecraft/world/entity/Shearable.java ++++ b/src/main/java/net/minecraft/world/entity/Shearable.java +@@ -8,4 +8,5 @@ public interface Shearable { + void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears); + + boolean readyForShearing(); ++ net.minecraft.world.level.Level level(); // Shearable API - expose default level needed for shearing. + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java +index 0139e85c0751564bb4d2847b7b2e48f75fee9e53..e8e4704304504e69c7964dcd4df8ce5db9e92bf6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java +@@ -4,7 +4,7 @@ import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Bogged; + import org.bukkit.entity.Skeleton; + +-public class CraftBogged extends CraftAbstractSkeleton implements Bogged { ++public class CraftBogged extends CraftAbstractSkeleton implements Bogged, io.papermc.paper.entity.PaperShearable { // Paper - Shear API + + public CraftBogged(CraftServer server, net.minecraft.world.entity.monster.Bogged entity) { + super(server, entity); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java +index 901b751c856dea677d5238db1ee70401a9d7bba5..bfe39c7a9d2910bee9b40cf5ab4c154711d5cbb0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java +@@ -14,7 +14,7 @@ import org.bukkit.entity.MushroomCow; + import org.bukkit.potion.PotionEffect; + import org.bukkit.potion.PotionEffectType; + +-public class CraftMushroomCow extends CraftCow implements MushroomCow { ++public class CraftMushroomCow extends CraftCow implements MushroomCow, io.papermc.paper.entity.PaperShearable { // Paper + public CraftMushroomCow(CraftServer server, net.minecraft.world.entity.animal.MushroomCow entity) { + super(server, entity); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java +index 030bf7b6312799231d0b614ba5c84fec23c276e3..37291d7ad9fdf0fe78894f82a418f40bb581f58b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java +@@ -4,7 +4,7 @@ import org.bukkit.DyeColor; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Sheep; + +-public class CraftSheep extends CraftAnimals implements Sheep { ++public class CraftSheep extends CraftAnimals implements Sheep, io.papermc.paper.entity.PaperShearable { // Paper + public CraftSheep(CraftServer server, net.minecraft.world.entity.animal.Sheep entity) { + super(server, entity); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java +index 1e9807b8f468742d208f817e22d7625106fc1b58..4ce2373ff71c3c1b8951646e057587a3ab09e145 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java +@@ -4,7 +4,7 @@ import net.minecraft.world.entity.animal.SnowGolem; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Snowman; + +-public class CraftSnowman extends CraftGolem implements Snowman, com.destroystokyo.paper.entity.CraftRangedEntity { // Paper ++public class CraftSnowman extends CraftGolem implements Snowman, com.destroystokyo.paper.entity.CraftRangedEntity, io.papermc.paper.entity.PaperShearable { // Paper + public CraftSnowman(CraftServer server, SnowGolem entity) { + super(server, entity); + } +diff --git a/src/test/java/io/papermc/paper/entity/ShearableTest.java b/src/test/java/io/papermc/paper/entity/ShearableTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..709b90f0cd01a4508d44f2e971f5bf9785d78ae5 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/entity/ShearableTest.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.entity; ++ ++import com.destroystokyo.paper.entity.ai.MobGoalHelper; ++import io.github.classgraph.ClassGraph; ++import io.github.classgraph.ScanResult; ++import java.util.List; ++import net.minecraft.world.entity.Mob; ++import net.minecraft.world.entity.Shearable; ++import org.bukkit.support.environment.Normal; ++import org.junit.jupiter.api.Assertions; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++@Normal ++class ShearableTest { ++ ++ static List> nmsShearables() { ++ try (final ScanResult result = new ClassGraph().enableClassInfo().whitelistPackages("net.minecraft.world.entity").scan()) { ++ return result.getClassesImplementing(Shearable.class.getName()).loadClasses(Shearable.class); ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ @ParameterizedTest ++ @MethodSource("nmsShearables") ++ void ensureImplementsShearable(final Class shearableNmsClass) { ++ final Class bukkitClass = MobGoalHelper.toBukkitClass((Class) shearableNmsClass); ++ Assertions.assertTrue(io.papermc.paper.entity.Shearable.class.isAssignableFrom(bukkitClass), bukkitClass.getName() + " does not implement Shearable"); ++ } ++} diff --git a/patches/server/0795-Fix-inventories-returning-null-Locations.patch b/patches/server/0795-Fix-inventories-returning-null-Locations.patch deleted file mode 100644 index 1a65689fad..0000000000 --- a/patches/server/0795-Fix-inventories-returning-null-Locations.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 15 Mar 2023 18:29:45 -0700 -Subject: [PATCH] Fix inventories returning null Locations - -Wandering Trader, AbstractHorse, Beacon and Composter inventories returned null locations -when a block or entity location is readily available - -Co-authored-by: Lukas Planz - -diff --git a/src/main/java/net/minecraft/world/SimpleContainer.java b/src/main/java/net/minecraft/world/SimpleContainer.java -index 13a32ef8f86b678dcce83c41c78b47d9aab9f16b..b0963c534afe5be164701cb283f1849e32ae5a86 100644 ---- a/src/main/java/net/minecraft/world/SimpleContainer.java -+++ b/src/main/java/net/minecraft/world/SimpleContainer.java -@@ -63,6 +63,16 @@ public class SimpleContainer implements Container, StackedContentsCompatible { - - @Override - public Location getLocation() { -+ // Paper start - Fix inventories returning null Locations -+ // When the block inventory does not have a tile state that implements getLocation, e. g. composters -+ if (this.bukkitOwner instanceof org.bukkit.inventory.BlockInventoryHolder blockInventoryHolder) { -+ return blockInventoryHolder.getBlock().getLocation(); -+ } -+ // When the bukkit owner is a bukkit entity, but does not implement Container itself, e. g. horses -+ if (this.bukkitOwner instanceof org.bukkit.entity.Entity entity) { -+ return entity.getLocation(); -+ } -+ // Paper end - Fix inventories returning null Locations - return null; - } - -diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -index 9db647cfbd3f9c884465cf3d3a1b911d46a3da58..c0dfa04511110be366ee5b0bd75efc51afcce2e4 100644 ---- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -@@ -52,6 +52,12 @@ public class BeaconMenu extends AbstractContainerMenu { - public int getMaxStackSize() { - return 1; - } -+ // Paper start - Fix inventories returning null Locations -+ @Override -+ public org.bukkit.Location getLocation() { -+ return context.getLocation(); -+ } -+ // Paper end - Fix inventories returning null Locations - }; - checkContainerDataCount(propertyDelegate, 3); - this.beaconData = propertyDelegate; -diff --git a/src/main/java/net/minecraft/world/inventory/MerchantContainer.java b/src/main/java/net/minecraft/world/inventory/MerchantContainer.java -index 7cc96b62f6bacdb44a37d74db214bd0e11c4d503..9140fab07aab32065f7a3b5d13dd17d61dc6d646 100644 ---- a/src/main/java/net/minecraft/world/inventory/MerchantContainer.java -+++ b/src/main/java/net/minecraft/world/inventory/MerchantContainer.java -@@ -65,7 +65,7 @@ public class MerchantContainer implements Container { - - @Override - public Location getLocation() { -- return (this.merchant instanceof Villager) ? ((Villager) this.merchant).getBukkitEntity().getLocation() : null; -+ return (this.merchant instanceof AbstractVillager) ? ((AbstractVillager) this.merchant).getBukkitEntity().getLocation() : null; // Paper - Fix inventories returning null Locations - } - // CraftBukkit end - diff --git a/patches/server/0796-Add-Shearable-API.patch b/patches/server/0796-Add-Shearable-API.patch deleted file mode 100644 index 302cec90c2..0000000000 --- a/patches/server/0796-Add-Shearable-API.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 17 Oct 2021 15:39:48 -0400 -Subject: [PATCH] Add Shearable API - - -diff --git a/src/main/java/io/papermc/paper/entity/PaperShearable.java b/src/main/java/io/papermc/paper/entity/PaperShearable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b02e2f2ea4f83615897cb4c66be8b29948097815 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/entity/PaperShearable.java -@@ -0,0 +1,25 @@ -+package io.papermc.paper.entity; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import net.kyori.adventure.sound.Sound; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.entity.Shearable; -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.item.Items; -+import org.jetbrains.annotations.NotNull; -+ -+public interface PaperShearable extends io.papermc.paper.entity.Shearable { -+ -+ Shearable getHandle(); -+ -+ @Override -+ default boolean readyToBeSheared() { -+ return this.getHandle().readyForShearing(); -+ } -+ -+ @Override -+ default void shear(@NotNull Sound.Source source) { -+ if (!(this.getHandle().level() instanceof final ServerLevel serverLevel)) return; -+ this.getHandle().shear(serverLevel, PaperAdventure.asVanilla(source), new ItemStack(Items.SHEARS)); -+ } -+} -diff --git a/src/main/java/net/minecraft/world/entity/Shearable.java b/src/main/java/net/minecraft/world/entity/Shearable.java -index a3095eee48d8b87a35ad35da9c8a2a9ca20c92bc..35076593f3ccd651295ae1fc9bcf8256c19672dd 100644 ---- a/src/main/java/net/minecraft/world/entity/Shearable.java -+++ b/src/main/java/net/minecraft/world/entity/Shearable.java -@@ -8,4 +8,5 @@ public interface Shearable { - void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears); - - boolean readyForShearing(); -+ net.minecraft.world.level.Level level(); // Shearable API - expose default level needed for shearing. - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java -index 0139e85c0751564bb4d2847b7b2e48f75fee9e53..e8e4704304504e69c7964dcd4df8ce5db9e92bf6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBogged.java -@@ -4,7 +4,7 @@ import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Bogged; - import org.bukkit.entity.Skeleton; - --public class CraftBogged extends CraftAbstractSkeleton implements Bogged { -+public class CraftBogged extends CraftAbstractSkeleton implements Bogged, io.papermc.paper.entity.PaperShearable { // Paper - Shear API - - public CraftBogged(CraftServer server, net.minecraft.world.entity.monster.Bogged entity) { - super(server, entity); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java -index 901b751c856dea677d5238db1ee70401a9d7bba5..bfe39c7a9d2910bee9b40cf5ab4c154711d5cbb0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java -@@ -14,7 +14,7 @@ import org.bukkit.entity.MushroomCow; - import org.bukkit.potion.PotionEffect; - import org.bukkit.potion.PotionEffectType; - --public class CraftMushroomCow extends CraftCow implements MushroomCow { -+public class CraftMushroomCow extends CraftCow implements MushroomCow, io.papermc.paper.entity.PaperShearable { // Paper - public CraftMushroomCow(CraftServer server, net.minecraft.world.entity.animal.MushroomCow entity) { - super(server, entity); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java -index 030bf7b6312799231d0b614ba5c84fec23c276e3..37291d7ad9fdf0fe78894f82a418f40bb581f58b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java -@@ -4,7 +4,7 @@ import org.bukkit.DyeColor; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Sheep; - --public class CraftSheep extends CraftAnimals implements Sheep { -+public class CraftSheep extends CraftAnimals implements Sheep, io.papermc.paper.entity.PaperShearable { // Paper - public CraftSheep(CraftServer server, net.minecraft.world.entity.animal.Sheep entity) { - super(server, entity); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java -index 1e9807b8f468742d208f817e22d7625106fc1b58..4ce2373ff71c3c1b8951646e057587a3ab09e145 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java -@@ -4,7 +4,7 @@ import net.minecraft.world.entity.animal.SnowGolem; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Snowman; - --public class CraftSnowman extends CraftGolem implements Snowman, com.destroystokyo.paper.entity.CraftRangedEntity { // Paper -+public class CraftSnowman extends CraftGolem implements Snowman, com.destroystokyo.paper.entity.CraftRangedEntity, io.papermc.paper.entity.PaperShearable { // Paper - public CraftSnowman(CraftServer server, SnowGolem entity) { - super(server, entity); - } -diff --git a/src/test/java/io/papermc/paper/entity/ShearableTest.java b/src/test/java/io/papermc/paper/entity/ShearableTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..709b90f0cd01a4508d44f2e971f5bf9785d78ae5 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/entity/ShearableTest.java -@@ -0,0 +1,30 @@ -+package io.papermc.paper.entity; -+ -+import com.destroystokyo.paper.entity.ai.MobGoalHelper; -+import io.github.classgraph.ClassGraph; -+import io.github.classgraph.ScanResult; -+import java.util.List; -+import net.minecraft.world.entity.Mob; -+import net.minecraft.world.entity.Shearable; -+import org.bukkit.support.environment.Normal; -+import org.junit.jupiter.api.Assertions; -+import org.junit.jupiter.params.ParameterizedTest; -+import org.junit.jupiter.params.provider.MethodSource; -+ -+@Normal -+class ShearableTest { -+ -+ static List> nmsShearables() { -+ try (final ScanResult result = new ClassGraph().enableClassInfo().whitelistPackages("net.minecraft.world.entity").scan()) { -+ return result.getClassesImplementing(Shearable.class.getName()).loadClasses(Shearable.class); -+ } -+ } -+ -+ @SuppressWarnings("unchecked") -+ @ParameterizedTest -+ @MethodSource("nmsShearables") -+ void ensureImplementsShearable(final Class shearableNmsClass) { -+ final Class bukkitClass = MobGoalHelper.toBukkitClass((Class) shearableNmsClass); -+ Assertions.assertTrue(io.papermc.paper.entity.Shearable.class.isAssignableFrom(bukkitClass), bukkitClass.getName() + " does not implement Shearable"); -+ } -+} diff --git a/patches/server/0796-Fix-SpawnEggMeta-get-setSpawnedType.patch b/patches/server/0796-Fix-SpawnEggMeta-get-setSpawnedType.patch new file mode 100644 index 0000000000..254a94df3a --- /dev/null +++ b/patches/server/0796-Fix-SpawnEggMeta-get-setSpawnedType.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 23 Feb 2023 13:19:13 -0800 +Subject: [PATCH] Fix SpawnEggMeta#get/setSpawnedType + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +index ea9937ad27817112f71e8a0a816865961ce19a61..6c2c3b514be0dab47f3e44f65bdc6a3574e59b7c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +@@ -94,6 +94,30 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { + public void setSpawnedType(EntityType type) { + throw new UnsupportedOperationException("Must change item type to set spawned type"); + } ++ // Paper start ++ @Override ++ public EntityType getCustomSpawnedType() { ++ return java.util.Optional.ofNullable(this.entityTag) ++ .map(tag -> tag.getString(ENTITY_ID.NBT)) ++ .map(net.minecraft.resources.ResourceLocation::tryParse) ++ .map(key -> key.getNamespace().equals("minecraft") ? EntityType.fromName(key.getPath()) : null) ++ .orElse(null); ++ } ++ ++ @Override ++ public void setCustomSpawnedType(final EntityType type) { ++ if (type == null) { ++ if (this.entityTag != null) { ++ this.entityTag.remove(ENTITY_ID.NBT); ++ } ++ } else { ++ if (this.entityTag == null) { ++ this.entityTag = new CompoundTag(); ++ } ++ this.entityTag.putString(ENTITY_ID.NBT, type.key().toString()); ++ } ++ } ++ // Paper end + + @Override + public EntitySnapshot getSpawnedEntity() { diff --git a/patches/server/0797-Fix-SpawnEggMeta-get-setSpawnedType.patch b/patches/server/0797-Fix-SpawnEggMeta-get-setSpawnedType.patch deleted file mode 100644 index 254a94df3a..0000000000 --- a/patches/server/0797-Fix-SpawnEggMeta-get-setSpawnedType.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 23 Feb 2023 13:19:13 -0800 -Subject: [PATCH] Fix SpawnEggMeta#get/setSpawnedType - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -index ea9937ad27817112f71e8a0a816865961ce19a61..6c2c3b514be0dab47f3e44f65bdc6a3574e59b7c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -@@ -94,6 +94,30 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { - public void setSpawnedType(EntityType type) { - throw new UnsupportedOperationException("Must change item type to set spawned type"); - } -+ // Paper start -+ @Override -+ public EntityType getCustomSpawnedType() { -+ return java.util.Optional.ofNullable(this.entityTag) -+ .map(tag -> tag.getString(ENTITY_ID.NBT)) -+ .map(net.minecraft.resources.ResourceLocation::tryParse) -+ .map(key -> key.getNamespace().equals("minecraft") ? EntityType.fromName(key.getPath()) : null) -+ .orElse(null); -+ } -+ -+ @Override -+ public void setCustomSpawnedType(final EntityType type) { -+ if (type == null) { -+ if (this.entityTag != null) { -+ this.entityTag.remove(ENTITY_ID.NBT); -+ } -+ } else { -+ if (this.entityTag == null) { -+ this.entityTag = new CompoundTag(); -+ } -+ this.entityTag.putString(ENTITY_ID.NBT, type.key().toString()); -+ } -+ } -+ // Paper end - - @Override - public EntitySnapshot getSpawnedEntity() { diff --git a/patches/server/0797-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch b/patches/server/0797-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch new file mode 100644 index 0000000000..72035f8c0e --- /dev/null +++ b/patches/server/0797-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 19 Mar 2023 20:36:22 -0700 +Subject: [PATCH] Fix crash relating to bad recipes in furnace-like tile + entities + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +index 4d36aa195332c2ff6fa7bc5fff61ff7dc80a3fd5..b1067a3add5dc0cfa853b02b5b556d6d67e2932a 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +@@ -499,6 +499,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + Entry>> entry = (Entry) objectiterator.next(); + + worldserver.recipeAccess().byKey(entry.getKey()).ifPresent((recipeholder) -> { // CraftBukkit - decompile error ++ if (!(recipeholder.value() instanceof AbstractCookingRecipe)) return; // Paper - don't process non-cooking recipes + list.add(recipeholder); + AbstractFurnaceBlockEntity.createExperience(worldserver, vec3d, entry.getIntValue(), ((AbstractCookingRecipe) recipeholder.value()).experience(), blockposition, entityplayer, itemstack, amount); // CraftBukkit + }); diff --git a/patches/server/0798-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch b/patches/server/0798-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch deleted file mode 100644 index 72035f8c0e..0000000000 --- a/patches/server/0798-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 19 Mar 2023 20:36:22 -0700 -Subject: [PATCH] Fix crash relating to bad recipes in furnace-like tile - entities - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index 4d36aa195332c2ff6fa7bc5fff61ff7dc80a3fd5..b1067a3add5dc0cfa853b02b5b556d6d67e2932a 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -499,6 +499,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - Entry>> entry = (Entry) objectiterator.next(); - - worldserver.recipeAccess().byKey(entry.getKey()).ifPresent((recipeholder) -> { // CraftBukkit - decompile error -+ if (!(recipeholder.value() instanceof AbstractCookingRecipe)) return; // Paper - don't process non-cooking recipes - list.add(recipeholder); - AbstractFurnaceBlockEntity.createExperience(worldserver, vec3d, entry.getIntValue(), ((AbstractCookingRecipe) recipeholder.value()).experience(), blockposition, entityplayer, itemstack, amount); // CraftBukkit - }); diff --git a/patches/server/0798-Treat-sequence-violations-like-they-should-be.patch b/patches/server/0798-Treat-sequence-violations-like-they-should-be.patch new file mode 100644 index 0000000000..2a7a2399bc --- /dev/null +++ b/patches/server/0798-Treat-sequence-violations-like-they-should-be.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Thu, 30 Mar 2023 03:13:58 +0100 +Subject: [PATCH] Treat sequence violations like they should be + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 5802bca38fdeccbc1353990ecb425034f86e8332..3e9247f662afde4dcca900b69b6a78140f9566fa 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1997,6 +1997,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + public void ackBlockChangesUpTo(int sequence) { + if (sequence < 0) { ++ this.disconnect(Component.literal("Expected packet sequence nr >= 0"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - Treat sequence violations like they should be + throw new IllegalArgumentException("Expected packet sequence nr >= 0"); + } else { + this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo); diff --git a/patches/server/0799-Prevent-causing-expired-keys-from-impacting-new-join.patch b/patches/server/0799-Prevent-causing-expired-keys-from-impacting-new-join.patch new file mode 100644 index 0000000000..7a5bcdc7de --- /dev/null +++ b/patches/server/0799-Prevent-causing-expired-keys-from-impacting-new-join.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Mon, 3 Apr 2023 08:55:52 +0100 +Subject: [PATCH] Prevent causing expired keys from impacting new joins + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java +index d0b2a8b5ded71a9a41753f4addea1c49826b34a3..29b465fc1dc50e0e84ddb889c5303e80fe662874 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java +@@ -114,7 +114,15 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet serialized.chatSession = buf.readNullable(RemoteChatSession.Data::read), +- (buf, entry) -> buf.writeNullable(entry.chatSession, RemoteChatSession.Data::write) ++ // Paper start - Prevent causing expired keys from impacting new joins ++ (buf, entry) -> { ++ RemoteChatSession.Data chatSession = entry.chatSession; ++ if (chatSession != null && chatSession.profilePublicKey().hasExpired()) { ++ chatSession = null; ++ } ++ buf.writeNullable(chatSession, RemoteChatSession.Data::write); ++ } ++ // Paper end - Prevent causing expired keys from impacting new joins + ), + UPDATE_GAME_MODE((serialized, buf) -> serialized.gameMode = GameType.byId(buf.readVarInt()), (buf, entry) -> buf.writeVarInt(entry.gameMode().getId())), + UPDATE_LISTED((serialized, buf) -> serialized.listed = buf.readBoolean(), (buf, entry) -> buf.writeBoolean(entry.listed())), +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 3e9247f662afde4dcca900b69b6a78140f9566fa..919b0ffb69720b3edeb9d25c7f41291a09976505 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -305,6 +305,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + private boolean receivedMovementThisTick; + @Nullable + private RemoteChatSession chatSession; ++ private boolean hasLoggedExpiry = false; // Paper - Prevent causing expired keys from impacting new joins + private SignedMessageChain.Decoder signedMessageDecoder; + private final LastSeenMessagesValidator lastSeenMessages = new LastSeenMessagesValidator(20); + private final MessageSignatureCache messageSignatureCache = MessageSignatureCache.createDefault(); +@@ -401,6 +402,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause + } + ++ // Paper start - Prevent causing expired keys from impacting new joins ++ if (!hasLoggedExpiry && this.chatSession != null && this.chatSession.profilePublicKey().data().hasExpired()) { ++ LOGGER.info("Player profile key for {} has expired!", this.player.getName().getString()); ++ hasLoggedExpiry = true; ++ } ++ // Paper end - Prevent causing expired keys from impacting new joins ++ + } + + private int getMaximumFlyingTicks(Entity vehicle) { +@@ -3484,6 +3492,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + private void resetPlayerChatState(RemoteChatSession session) { + this.chatSession = session; ++ this.hasLoggedExpiry = false; // Paper - Prevent causing expired keys from impacting new joins + this.signedMessageDecoder = session.createMessageDecoder(this.player.getUUID()); + this.chatMessageChain.append(() -> { + this.player.setChatSession(session); diff --git a/patches/server/0799-Treat-sequence-violations-like-they-should-be.patch b/patches/server/0799-Treat-sequence-violations-like-they-should-be.patch deleted file mode 100644 index 387f4dcf4f..0000000000 --- a/patches/server/0799-Treat-sequence-violations-like-they-should-be.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Thu, 30 Mar 2023 03:13:58 +0100 -Subject: [PATCH] Treat sequence violations like they should be - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 51f4d1e5c02c516b5c57095d35348ba53f5b3193..c2328bc821730dd829440ab17b7c8b1800a1f5ca 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1997,6 +1997,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - public void ackBlockChangesUpTo(int sequence) { - if (sequence < 0) { -+ this.disconnect(Component.literal("Expected packet sequence nr >= 0"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - Treat sequence violations like they should be - throw new IllegalArgumentException("Expected packet sequence nr >= 0"); - } else { - this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo); diff --git a/patches/server/0800-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch b/patches/server/0800-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch new file mode 100644 index 0000000000..5ddc60ef91 --- /dev/null +++ b/patches/server/0800-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Wed, 5 Apr 2023 20:15:47 +0100 +Subject: [PATCH] Prevent GameEvents being fired from unloaded chunks + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index b81d814619e4175f42aee397811b07cae420c2e8..e9096a138175448279a03a55043982b6d83fbe12 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1355,6 +1355,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + @Override + public void gameEvent(Holder event, Vec3 emitterPos, GameEvent.Context emitter) { ++ // Paper start - Prevent GameEvents being fired from unloaded chunks ++ if (this.getChunkIfLoadedImmediately((Mth.floor(emitterPos.x) >> 4), (Mth.floor(emitterPos.z) >> 4)) == null) { ++ return; ++ } ++ // Paper end - Prevent GameEvents being fired from unloaded chunks + this.gameEventDispatcher.post(event, emitterPos, emitter); + } + diff --git a/patches/server/0800-Prevent-causing-expired-keys-from-impacting-new-join.patch b/patches/server/0800-Prevent-causing-expired-keys-from-impacting-new-join.patch deleted file mode 100644 index 2001b0974c..0000000000 --- a/patches/server/0800-Prevent-causing-expired-keys-from-impacting-new-join.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Mon, 3 Apr 2023 08:55:52 +0100 -Subject: [PATCH] Prevent causing expired keys from impacting new joins - - -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -index d0b2a8b5ded71a9a41753f4addea1c49826b34a3..29b465fc1dc50e0e84ddb889c5303e80fe662874 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -@@ -114,7 +114,15 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet serialized.chatSession = buf.readNullable(RemoteChatSession.Data::read), -- (buf, entry) -> buf.writeNullable(entry.chatSession, RemoteChatSession.Data::write) -+ // Paper start - Prevent causing expired keys from impacting new joins -+ (buf, entry) -> { -+ RemoteChatSession.Data chatSession = entry.chatSession; -+ if (chatSession != null && chatSession.profilePublicKey().hasExpired()) { -+ chatSession = null; -+ } -+ buf.writeNullable(chatSession, RemoteChatSession.Data::write); -+ } -+ // Paper end - Prevent causing expired keys from impacting new joins - ), - UPDATE_GAME_MODE((serialized, buf) -> serialized.gameMode = GameType.byId(buf.readVarInt()), (buf, entry) -> buf.writeVarInt(entry.gameMode().getId())), - UPDATE_LISTED((serialized, buf) -> serialized.listed = buf.readBoolean(), (buf, entry) -> buf.writeBoolean(entry.listed())), -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index c2328bc821730dd829440ab17b7c8b1800a1f5ca..60d58622fd568932c019ba6a4e4070a881fdda53 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -305,6 +305,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private boolean receivedMovementThisTick; - @Nullable - private RemoteChatSession chatSession; -+ private boolean hasLoggedExpiry = false; // Paper - Prevent causing expired keys from impacting new joins - private SignedMessageChain.Decoder signedMessageDecoder; - private final LastSeenMessagesValidator lastSeenMessages = new LastSeenMessagesValidator(20); - private final MessageSignatureCache messageSignatureCache = MessageSignatureCache.createDefault(); -@@ -401,6 +402,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause - } - -+ // Paper start - Prevent causing expired keys from impacting new joins -+ if (!hasLoggedExpiry && this.chatSession != null && this.chatSession.profilePublicKey().data().hasExpired()) { -+ LOGGER.info("Player profile key for {} has expired!", this.player.getName().getString()); -+ hasLoggedExpiry = true; -+ } -+ // Paper end - Prevent causing expired keys from impacting new joins -+ - } - - private int getMaximumFlyingTicks(Entity vehicle) { -@@ -3487,6 +3495,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - private void resetPlayerChatState(RemoteChatSession session) { - this.chatSession = session; -+ this.hasLoggedExpiry = false; // Paper - Prevent causing expired keys from impacting new joins - this.signedMessageDecoder = session.createMessageDecoder(this.player.getUUID()); - this.chatMessageChain.append(() -> { - this.player.setChatSession(session); diff --git a/patches/server/0801-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch b/patches/server/0801-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch deleted file mode 100644 index bb2d2b2c31..0000000000 --- a/patches/server/0801-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Wed, 5 Apr 2023 20:15:47 +0100 -Subject: [PATCH] Prevent GameEvents being fired from unloaded chunks - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 79acbaf880d5f47efd210627a60ce1e930b63e39..537a755d097d7713404d83dc47cd17828b15a906 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1385,6 +1385,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - @Override - public void gameEvent(Holder event, Vec3 emitterPos, GameEvent.Context emitter) { -+ // Paper start - Prevent GameEvents being fired from unloaded chunks -+ if (this.getChunkIfLoadedImmediately((Mth.floor(emitterPos.x) >> 4), (Mth.floor(emitterPos.z) >> 4)) == null) { -+ return; -+ } -+ // Paper end - Prevent GameEvents being fired from unloaded chunks - this.gameEventDispatcher.post(event, emitterPos, emitter); - } - diff --git a/patches/server/0801-Use-array-for-gamerule-storage.patch b/patches/server/0801-Use-array-for-gamerule-storage.patch new file mode 100644 index 0000000000..efb6cfeb50 --- /dev/null +++ b/patches/server/0801-Use-array-for-gamerule-storage.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Sun, 9 May 2021 16:49:49 -0500 +Subject: [PATCH] Use array for gamerule storage + + +diff --git a/src/main/java/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java +index 09299e45552eb998fd02123c3921c0653f85083d..4ae47c2c5a6bcfbf932d000a80974463e2d3818d 100644 +--- a/src/main/java/net/minecraft/world/level/GameRules.java ++++ b/src/main/java/net/minecraft/world/level/GameRules.java +@@ -129,6 +129,7 @@ public class GameRules { + })); + private final Map, GameRules.Value> rules; + private final FeatureFlagSet enabledFeatures; ++ private final GameRules.Value[] gameruleArray; // Paper - Perf: Use array for gamerule storage + + private static > GameRules.Key register(String name, GameRules.Category category, GameRules.Type type) { + GameRules.Key gamerules_gamerulekey = new GameRules.Key<>(name, category); +@@ -161,10 +162,21 @@ public class GameRules { + private GameRules(Map, GameRules.Value> rules, FeatureFlagSet enabledFeatures) { + this.rules = rules; + this.enabledFeatures = enabledFeatures; ++ ++ // Paper start - Perf: Use array for gamerule storage ++ int arraySize = GameRules.Key.lastGameRuleIndex + 1; ++ GameRules.Value[] values = new GameRules.Value[arraySize]; ++ ++ for (Entry, GameRules.Value> entry : rules.entrySet()) { ++ values[entry.getKey().gameRuleIndex] = entry.getValue(); ++ } ++ ++ this.gameruleArray = values; ++ // Paper end - Perf: Use array for gamerule storage + } + + public > T getRule(GameRules.Key key) { +- T t0 = (T) this.rules.get(key); // CraftBukkit - decompile error ++ T t0 = key == null ? null : (T) this.gameruleArray[key.gameRuleIndex]; // Paper - Perf: Use array for gamerule storage + + if (t0 == null) { + throw new IllegalArgumentException("Tried to access invalid game rule"); +@@ -232,6 +244,10 @@ public class GameRules { + } + + public static final class Key> { ++ // Paper start - Perf: Use array for gamerule storage ++ public static int lastGameRuleIndex = 0; ++ public final int gameRuleIndex = lastGameRuleIndex++; ++ // Paper end - Perf: Use array for gamerule storage + + final String id; + private final GameRules.Category category; diff --git a/patches/server/0802-Fix-a-couple-of-upstream-bed-issues.patch b/patches/server/0802-Fix-a-couple-of-upstream-bed-issues.patch new file mode 100644 index 0000000000..76cfa7bc0d --- /dev/null +++ b/patches/server/0802-Fix-a-couple-of-upstream-bed-issues.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 9 Apr 2023 21:11:58 -0700 +Subject: [PATCH] Fix a couple of upstream bed issues + +Upstream incorrectly skipped explosion logic if +the bed was occupied and added a "feature" where +if you set your spawn in a respawn anchor world +but then replaced it with a bed, you could respawn +at the bed in that world. + +diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java +index b09fa473426a6c7e006a071827e5a68560d6c685..c02c4834ace843633b77fb43eeadd3ddc7b1f743 100644 +--- a/src/main/java/net/minecraft/world/level/block/BedBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java +@@ -109,6 +109,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock + world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); + return InteractionResult.SUCCESS_SERVER; + } else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) { ++ if (!BedBlock.canSetSpawn(world)) return this.explodeBed(state, world, pos); // Paper - check explode first + if (!this.kickVillagerOutOfBed(world, pos)) { + player.displayClientMessage(Component.translatable("block.minecraft.bed.occupied"), true); + } +@@ -166,8 +167,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock + // CraftBukkit end + + public static boolean canSetSpawn(Level world) { +- // CraftBukkit - moved world and biome check into EntityHuman +- return true || world.dimensionType().bedWorks(); ++ return world.dimensionType().bedWorks(); // Paper - actually check if the bed works + } + + private boolean kickVillagerOutOfBed(Level world, BlockPos pos) { diff --git a/patches/server/0802-Use-array-for-gamerule-storage.patch b/patches/server/0802-Use-array-for-gamerule-storage.patch deleted file mode 100644 index efb6cfeb50..0000000000 --- a/patches/server/0802-Use-array-for-gamerule-storage.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paul Sauve -Date: Sun, 9 May 2021 16:49:49 -0500 -Subject: [PATCH] Use array for gamerule storage - - -diff --git a/src/main/java/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java -index 09299e45552eb998fd02123c3921c0653f85083d..4ae47c2c5a6bcfbf932d000a80974463e2d3818d 100644 ---- a/src/main/java/net/minecraft/world/level/GameRules.java -+++ b/src/main/java/net/minecraft/world/level/GameRules.java -@@ -129,6 +129,7 @@ public class GameRules { - })); - private final Map, GameRules.Value> rules; - private final FeatureFlagSet enabledFeatures; -+ private final GameRules.Value[] gameruleArray; // Paper - Perf: Use array for gamerule storage - - private static > GameRules.Key register(String name, GameRules.Category category, GameRules.Type type) { - GameRules.Key gamerules_gamerulekey = new GameRules.Key<>(name, category); -@@ -161,10 +162,21 @@ public class GameRules { - private GameRules(Map, GameRules.Value> rules, FeatureFlagSet enabledFeatures) { - this.rules = rules; - this.enabledFeatures = enabledFeatures; -+ -+ // Paper start - Perf: Use array for gamerule storage -+ int arraySize = GameRules.Key.lastGameRuleIndex + 1; -+ GameRules.Value[] values = new GameRules.Value[arraySize]; -+ -+ for (Entry, GameRules.Value> entry : rules.entrySet()) { -+ values[entry.getKey().gameRuleIndex] = entry.getValue(); -+ } -+ -+ this.gameruleArray = values; -+ // Paper end - Perf: Use array for gamerule storage - } - - public > T getRule(GameRules.Key key) { -- T t0 = (T) this.rules.get(key); // CraftBukkit - decompile error -+ T t0 = key == null ? null : (T) this.gameruleArray[key.gameRuleIndex]; // Paper - Perf: Use array for gamerule storage - - if (t0 == null) { - throw new IllegalArgumentException("Tried to access invalid game rule"); -@@ -232,6 +244,10 @@ public class GameRules { - } - - public static final class Key> { -+ // Paper start - Perf: Use array for gamerule storage -+ public static int lastGameRuleIndex = 0; -+ public final int gameRuleIndex = lastGameRuleIndex++; -+ // Paper end - Perf: Use array for gamerule storage - - final String id; - private final GameRules.Category category; diff --git a/patches/server/0803-Fix-a-couple-of-upstream-bed-issues.patch b/patches/server/0803-Fix-a-couple-of-upstream-bed-issues.patch deleted file mode 100644 index 76cfa7bc0d..0000000000 --- a/patches/server/0803-Fix-a-couple-of-upstream-bed-issues.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 9 Apr 2023 21:11:58 -0700 -Subject: [PATCH] Fix a couple of upstream bed issues - -Upstream incorrectly skipped explosion logic if -the bed was occupied and added a "feature" where -if you set your spawn in a respawn anchor world -but then replaced it with a bed, you could respawn -at the bed in that world. - -diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java -index b09fa473426a6c7e006a071827e5a68560d6c685..c02c4834ace843633b77fb43eeadd3ddc7b1f743 100644 ---- a/src/main/java/net/minecraft/world/level/block/BedBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java -@@ -109,6 +109,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock - world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); - return InteractionResult.SUCCESS_SERVER; - } else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) { -+ if (!BedBlock.canSetSpawn(world)) return this.explodeBed(state, world, pos); // Paper - check explode first - if (!this.kickVillagerOutOfBed(world, pos)) { - player.displayClientMessage(Component.translatable("block.minecraft.bed.occupied"), true); - } -@@ -166,8 +167,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock - // CraftBukkit end - - public static boolean canSetSpawn(Level world) { -- // CraftBukkit - moved world and biome check into EntityHuman -- return true || world.dimensionType().bedWorks(); -+ return world.dimensionType().bedWorks(); // Paper - actually check if the bed works - } - - private boolean kickVillagerOutOfBed(Level world, BlockPos pos) { diff --git a/patches/server/0803-Fix-demo-flag-not-enabling-demo-mode.patch b/patches/server/0803-Fix-demo-flag-not-enabling-demo-mode.patch new file mode 100644 index 0000000000..1a72571965 --- /dev/null +++ b/patches/server/0803-Fix-demo-flag-not-enabling-demo-mode.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Fri, 7 Apr 2023 20:11:17 +0200 +Subject: [PATCH] Fix demo flag not enabling demo mode + +https://github.com/PaperMC/Paper/issues/9046 + +diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java +index 47cd7c66ac37efebf2f63c49d78dd8fe44a70ef8..fc6ce3485dc890f5105a37fe3e344a1460867556 100644 +--- a/src/main/java/net/minecraft/server/Main.java ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -325,7 +325,9 @@ public class Main { + + /* + dedicatedserver1.setPort((Integer) optionset.valueOf(optionspec11)); +- dedicatedserver1.setDemo(optionset.has(optionspec2)); ++ */ ++ dedicatedserver1.setDemo(optionset.has("demo")); // Paper ++ /* + dedicatedserver1.setId((String) optionset.valueOf(optionspec12)); + */ + boolean flag2 = !optionset.has("nogui") && !optionset.nonOptionArguments().contains("nogui"); diff --git a/patches/server/0804-Add-Mob-Experience-reward-API.patch b/patches/server/0804-Add-Mob-Experience-reward-API.patch new file mode 100644 index 0000000000..9e59c458f8 --- /dev/null +++ b/patches/server/0804-Add-Mob-Experience-reward-API.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: GodOfPro <1387ilia@gmail.com> +Date: Tue, 11 Apr 2023 16:31:39 +0430 +Subject: [PATCH] Add Mob Experience reward API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +index e226a99d00c990a4ca4f21b93fcae7a556e01dbb..95d7015a61098d1d22a501124d6bb8fba1516fe3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +@@ -168,4 +168,11 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { + this.getHandle().setAggressive(aggressive); + } + // Paper end ++ ++ // Paper start ++ @Override ++ public int getPossibleExperienceReward() { ++ return getHandle().getExperienceReward((net.minecraft.server.level.ServerLevel) this.getHandle().level(), null); ++ } ++ // Paper end + } diff --git a/patches/server/0804-Fix-demo-flag-not-enabling-demo-mode.patch b/patches/server/0804-Fix-demo-flag-not-enabling-demo-mode.patch deleted file mode 100644 index 1a72571965..0000000000 --- a/patches/server/0804-Fix-demo-flag-not-enabling-demo-mode.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Fri, 7 Apr 2023 20:11:17 +0200 -Subject: [PATCH] Fix demo flag not enabling demo mode - -https://github.com/PaperMC/Paper/issues/9046 - -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 47cd7c66ac37efebf2f63c49d78dd8fe44a70ef8..fc6ce3485dc890f5105a37fe3e344a1460867556 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -325,7 +325,9 @@ public class Main { - - /* - dedicatedserver1.setPort((Integer) optionset.valueOf(optionspec11)); -- dedicatedserver1.setDemo(optionset.has(optionspec2)); -+ */ -+ dedicatedserver1.setDemo(optionset.has("demo")); // Paper -+ /* - dedicatedserver1.setId((String) optionset.valueOf(optionspec12)); - */ - boolean flag2 = !optionset.has("nogui") && !optionset.nonOptionArguments().contains("nogui"); diff --git a/patches/server/0805-Add-Mob-Experience-reward-API.patch b/patches/server/0805-Add-Mob-Experience-reward-API.patch deleted file mode 100644 index 9e59c458f8..0000000000 --- a/patches/server/0805-Add-Mob-Experience-reward-API.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: GodOfPro <1387ilia@gmail.com> -Date: Tue, 11 Apr 2023 16:31:39 +0430 -Subject: [PATCH] Add Mob Experience reward API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -index e226a99d00c990a4ca4f21b93fcae7a556e01dbb..95d7015a61098d1d22a501124d6bb8fba1516fe3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -@@ -168,4 +168,11 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { - this.getHandle().setAggressive(aggressive); - } - // Paper end -+ -+ // Paper start -+ @Override -+ public int getPossibleExperienceReward() { -+ return getHandle().getExperienceReward((net.minecraft.server.level.ServerLevel) this.getHandle().level(), null); -+ } -+ // Paper end - } diff --git a/patches/server/0805-Break-redstone-on-top-of-trap-doors-early.patch b/patches/server/0805-Break-redstone-on-top-of-trap-doors-early.patch new file mode 100644 index 0000000000..ded460b32b --- /dev/null +++ b/patches/server/0805-Break-redstone-on-top-of-trap-doors-early.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 1 May 2023 18:31:26 -0700 +Subject: [PATCH] Break redstone on top of trap doors early + +This logic hooks into the neighbour update which should be invoked +as a result of redstone powering the trap door. + +diff --git a/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java b/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java +index a7d52f2f9c324c5af979fc39b3662ebc880e36fb..872e52e13293a99d45f93d90d8fa7f6aa99d1f3a 100644 +--- a/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java +@@ -157,7 +157,26 @@ public class TrapDoorBlock extends HorizontalDirectionalBlock implements SimpleW + flag1 = eventRedstone.getNewCurrent() > 0; + } + // CraftBukkit end +- if ((Boolean) state.getValue(TrapDoorBlock.OPEN) != flag1) { ++ // Paper start - break redstone on trapdoors early ++ boolean open = (Boolean) state.getValue(TrapDoorBlock.OPEN) != flag1; ++ // note: this must run before any state for this block/its neighborus are written to the world ++ // we allow the redstone event to fire so that plugins can block ++ if (flag1 && open) { // if we are now powered and it caused the trap door to open ++ // in this case, first check for the redstone on top first ++ BlockPos abovePos = pos.above(); ++ BlockState above = world.getBlockState(abovePos); ++ if (above.getBlock() instanceof RedStoneWireBlock) { ++ world.setBlock(abovePos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_NEIGHBORS); ++ Block.popResource(world, abovePos, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.REDSTONE)); ++ // now check that this didn't change our state ++ if (world.getBlockState(pos) != state) { ++ // our state was changed, so we cannot propagate this update ++ return; ++ } ++ } ++ } ++ if (open) { ++ // Paper end - break redstone on trapdoors early + state = (BlockState) state.setValue(TrapDoorBlock.OPEN, flag1); + this.playSound((Player) null, world, pos, flag1); + } diff --git a/patches/server/0806-Avoid-Lazy-Initialization-for-Enum-Fields.patch b/patches/server/0806-Avoid-Lazy-Initialization-for-Enum-Fields.patch new file mode 100644 index 0000000000..becde16ce8 --- /dev/null +++ b/patches/server/0806-Avoid-Lazy-Initialization-for-Enum-Fields.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 14 May 2023 00:47:28 -0400 +Subject: [PATCH] Avoid Lazy Initialization for Enum Fields + +This patch is meant to get rid of any instances of lazy initialization that Minecraft introduces for enums. +This has the possibility to create race condition issues, and generally don't make sense to be lazily done anyways. + +diff --git a/src/main/java/com/mojang/math/OctahedralGroup.java b/src/main/java/com/mojang/math/OctahedralGroup.java +index 0a3b6b8e250bd35530c05a1cdaf2eb8a9af4c72b..9aa82fc757c67a9456b2bdec744c0cb474d64df6 100644 +--- a/src/main/java/com/mojang/math/OctahedralGroup.java ++++ b/src/main/java/com/mojang/math/OctahedralGroup.java +@@ -110,6 +110,7 @@ public enum OctahedralGroup implements StringRepresentable { + this.permutation = axisTransformation; + this.transformation = new Matrix3f().scaling(flipX ? -1.0F : 1.0F, flipY ? -1.0F : 1.0F, flipZ ? -1.0F : 1.0F); + this.transformation.mul(axisTransformation.transformation()); ++ this.initializeRotationDirections(); // Paper - Avoid Lazy Initialization for Enum Fields + } + + private BooleanList packInversions() { +@@ -138,7 +139,7 @@ public enum OctahedralGroup implements StringRepresentable { + return this.name; + } + +- public Direction rotate(Direction direction) { ++ public void initializeRotationDirections() { // Paper - Avoid Lazy Initialization for Enum Fields + if (this.rotatedDirections == null) { + this.rotatedDirections = Maps.newEnumMap(Direction.class); + Direction.Axis[] axiss = Direction.Axis.values(); +@@ -153,6 +154,10 @@ public enum OctahedralGroup implements StringRepresentable { + } + } + ++ // Paper start - Avoid Lazy Initialization for Enum Fields ++ } ++ public Direction rotate(Direction direction) { ++ // Paper end - Avoid Lazy Initialization for Enum Fields + return this.rotatedDirections.get(direction); + } + diff --git a/patches/server/0806-Break-redstone-on-top-of-trap-doors-early.patch b/patches/server/0806-Break-redstone-on-top-of-trap-doors-early.patch deleted file mode 100644 index ded460b32b..0000000000 --- a/patches/server/0806-Break-redstone-on-top-of-trap-doors-early.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 1 May 2023 18:31:26 -0700 -Subject: [PATCH] Break redstone on top of trap doors early - -This logic hooks into the neighbour update which should be invoked -as a result of redstone powering the trap door. - -diff --git a/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java b/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java -index a7d52f2f9c324c5af979fc39b3662ebc880e36fb..872e52e13293a99d45f93d90d8fa7f6aa99d1f3a 100644 ---- a/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java -@@ -157,7 +157,26 @@ public class TrapDoorBlock extends HorizontalDirectionalBlock implements SimpleW - flag1 = eventRedstone.getNewCurrent() > 0; - } - // CraftBukkit end -- if ((Boolean) state.getValue(TrapDoorBlock.OPEN) != flag1) { -+ // Paper start - break redstone on trapdoors early -+ boolean open = (Boolean) state.getValue(TrapDoorBlock.OPEN) != flag1; -+ // note: this must run before any state for this block/its neighborus are written to the world -+ // we allow the redstone event to fire so that plugins can block -+ if (flag1 && open) { // if we are now powered and it caused the trap door to open -+ // in this case, first check for the redstone on top first -+ BlockPos abovePos = pos.above(); -+ BlockState above = world.getBlockState(abovePos); -+ if (above.getBlock() instanceof RedStoneWireBlock) { -+ world.setBlock(abovePos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_NEIGHBORS); -+ Block.popResource(world, abovePos, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.REDSTONE)); -+ // now check that this didn't change our state -+ if (world.getBlockState(pos) != state) { -+ // our state was changed, so we cannot propagate this update -+ return; -+ } -+ } -+ } -+ if (open) { -+ // Paper end - break redstone on trapdoors early - state = (BlockState) state.setValue(TrapDoorBlock.OPEN, flag1); - this.playSound((Player) null, world, pos, flag1); - } diff --git a/patches/server/0807-Avoid-Lazy-Initialization-for-Enum-Fields.patch b/patches/server/0807-Avoid-Lazy-Initialization-for-Enum-Fields.patch deleted file mode 100644 index becde16ce8..0000000000 --- a/patches/server/0807-Avoid-Lazy-Initialization-for-Enum-Fields.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 14 May 2023 00:47:28 -0400 -Subject: [PATCH] Avoid Lazy Initialization for Enum Fields - -This patch is meant to get rid of any instances of lazy initialization that Minecraft introduces for enums. -This has the possibility to create race condition issues, and generally don't make sense to be lazily done anyways. - -diff --git a/src/main/java/com/mojang/math/OctahedralGroup.java b/src/main/java/com/mojang/math/OctahedralGroup.java -index 0a3b6b8e250bd35530c05a1cdaf2eb8a9af4c72b..9aa82fc757c67a9456b2bdec744c0cb474d64df6 100644 ---- a/src/main/java/com/mojang/math/OctahedralGroup.java -+++ b/src/main/java/com/mojang/math/OctahedralGroup.java -@@ -110,6 +110,7 @@ public enum OctahedralGroup implements StringRepresentable { - this.permutation = axisTransformation; - this.transformation = new Matrix3f().scaling(flipX ? -1.0F : 1.0F, flipY ? -1.0F : 1.0F, flipZ ? -1.0F : 1.0F); - this.transformation.mul(axisTransformation.transformation()); -+ this.initializeRotationDirections(); // Paper - Avoid Lazy Initialization for Enum Fields - } - - private BooleanList packInversions() { -@@ -138,7 +139,7 @@ public enum OctahedralGroup implements StringRepresentable { - return this.name; - } - -- public Direction rotate(Direction direction) { -+ public void initializeRotationDirections() { // Paper - Avoid Lazy Initialization for Enum Fields - if (this.rotatedDirections == null) { - this.rotatedDirections = Maps.newEnumMap(Direction.class); - Direction.Axis[] axiss = Direction.Axis.values(); -@@ -153,6 +154,10 @@ public enum OctahedralGroup implements StringRepresentable { - } - } - -+ // Paper start - Avoid Lazy Initialization for Enum Fields -+ } -+ public Direction rotate(Direction direction) { -+ // Paper end - Avoid Lazy Initialization for Enum Fields - return this.rotatedDirections.get(direction); - } - diff --git a/patches/server/0807-More-accurate-isInOpenWater-impl.patch b/patches/server/0807-More-accurate-isInOpenWater-impl.patch new file mode 100644 index 0000000000..6e110094dd --- /dev/null +++ b/patches/server/0807-More-accurate-isInOpenWater-impl.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Sun, 7 May 2023 22:33:50 +0200 +Subject: [PATCH] More accurate isInOpenWater impl + +For fishing hooks, the openWater field is true by default, and only calculated when a "fish" is approaching the bobber. +This patch changes the API impl to calculate the open water state itself instead of returning this field. + +Relevant link: https://github.com/PaperMC/Paper/issues/9131 + +== AT == +public net.minecraft.world.entity.projectile.FishingHook calculateOpenWater(Lnet/minecraft/core/BlockPos;)Z +public net.minecraft.world.entity.projectile.FishingHook outOfWaterTime + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java +index 9d8f4b7176e60180565e3134a14ecf19060f2621..e0d65df2e5b4c14abeb89a5f72cc2d9fa034dcf5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java +@@ -164,7 +164,7 @@ public class CraftFishHook extends CraftProjectile implements FishHook { + + @Override + public boolean isInOpenWater() { +- return this.getHandle().isOpenWaterFishing(); ++ return this.getHandle().outOfWaterTime < 10 && this.getHandle().calculateOpenWater(this.getHandle().blockPosition()); // Paper - isOpenWaterFishing is only calculated when a "fish" is approaching the hook + } + + @Override diff --git a/patches/server/0808-Expand-PlayerItemMendEvent.patch b/patches/server/0808-Expand-PlayerItemMendEvent.patch new file mode 100644 index 0000000000..7c61c0095c --- /dev/null +++ b/patches/server/0808-Expand-PlayerItemMendEvent.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 20 Jan 2022 18:11:20 -0800 +Subject: [PATCH] Expand PlayerItemMendEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java +index 3a7af27bb1ce0cbe56bd3760cd400083daf98d4c..bf0838f574fa3fb9654e087d602b8d380bd7fb28 100644 +--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java ++++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java +@@ -358,7 +358,10 @@ public class ExperienceOrb extends Entity { + int j = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.serverLevel(), itemstack, amount); + int k = Math.min(j, itemstack.getDamageValue()); + // CraftBukkit start +- org.bukkit.event.player.PlayerItemMendEvent event = CraftEventFactory.callPlayerItemMendEvent(player, this, itemstack, optional.get().inSlot(), k); ++ // Paper start - mending event ++ final int consumedExperience = k > 0 ? k * amount / j : 0; ++ org.bukkit.event.player.PlayerItemMendEvent event = CraftEventFactory.callPlayerItemMendEvent(player, this, itemstack, optional.get().inSlot(), k, consumedExperience); ++ // Paper end - mending event + k = event.getRepairAmount(); + if (event.isCancelled()) { + return amount; +@@ -367,7 +370,7 @@ public class ExperienceOrb extends Entity { + + itemstack.setDamageValue(itemstack.getDamageValue() - k); + if (k > 0) { +- int l = amount - k * amount / j; ++ int l = amount - k * amount / j; // Paper - diff on change - expand PlayerMendEvents + + if (l > 0) { + // this.value = l; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls // Paper - the value field should not be mutated here because it doesn't take "count" into account +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 83e29f518a57bd2eb4113d5b93cdf47af119c715..0d2fd570463d7ad1b6457a8b14303273b97716dd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1883,11 +1883,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + handle.serverLevel(), itemstack, amount + ); + int i = Math.min(possibleDurabilityFromXp, itemstack.getDamageValue()); +- org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.get().inSlot(), i); ++ final int consumedExperience = i * amount / possibleDurabilityFromXp; // Paper - taken from ExperienceOrb#repairPlayerItems ++ org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.get().inSlot(), i, consumedExperience); + i = event.getRepairAmount(); + orb.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); + if (!event.isCancelled()) { +- amount -= i * amount / possibleDurabilityFromXp; ++ amount -= consumedExperience; // Use previously computed variable to reduce diff on change. + itemstack.setDamageValue(itemstack.getDamageValue() - i); + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index d63b9c666cf6eb1de114c5c89867b8d233267c9e..dd0d19faccbc49b5f9718e2df9f004bb17a9ef7e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1284,10 +1284,10 @@ public class CraftEventFactory { + return event; + } + +- public static PlayerItemMendEvent callPlayerItemMendEvent(net.minecraft.world.entity.player.Player entity, net.minecraft.world.entity.ExperienceOrb orb, net.minecraft.world.item.ItemStack nmsMendedItem, net.minecraft.world.entity.EquipmentSlot slot, int repairAmount) { ++ public static PlayerItemMendEvent callPlayerItemMendEvent(net.minecraft.world.entity.player.Player entity, net.minecraft.world.entity.ExperienceOrb orb, net.minecraft.world.item.ItemStack nmsMendedItem, net.minecraft.world.entity.EquipmentSlot slot, int repairAmount, int consumedExperience) { // Paper - Expand PlayerItemMendEvent + Player player = (Player) entity.getBukkitEntity(); + org.bukkit.inventory.ItemStack bukkitStack = CraftItemStack.asCraftMirror(nmsMendedItem); +- PlayerItemMendEvent event = new PlayerItemMendEvent(player, bukkitStack, CraftEquipmentSlot.getSlot(slot), (ExperienceOrb) orb.getBukkitEntity(), repairAmount); ++ PlayerItemMendEvent event = new PlayerItemMendEvent(player, bukkitStack, CraftEquipmentSlot.getSlot(slot), (ExperienceOrb) orb.getBukkitEntity(), repairAmount, consumedExperience); // Paper - Expand PlayerItemMendEvent + Bukkit.getPluginManager().callEvent(event); + return event; + } diff --git a/patches/server/0808-More-accurate-isInOpenWater-impl.patch b/patches/server/0808-More-accurate-isInOpenWater-impl.patch deleted file mode 100644 index 6e110094dd..0000000000 --- a/patches/server/0808-More-accurate-isInOpenWater-impl.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Sun, 7 May 2023 22:33:50 +0200 -Subject: [PATCH] More accurate isInOpenWater impl - -For fishing hooks, the openWater field is true by default, and only calculated when a "fish" is approaching the bobber. -This patch changes the API impl to calculate the open water state itself instead of returning this field. - -Relevant link: https://github.com/PaperMC/Paper/issues/9131 - -== AT == -public net.minecraft.world.entity.projectile.FishingHook calculateOpenWater(Lnet/minecraft/core/BlockPos;)Z -public net.minecraft.world.entity.projectile.FishingHook outOfWaterTime - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java -index 9d8f4b7176e60180565e3134a14ecf19060f2621..e0d65df2e5b4c14abeb89a5f72cc2d9fa034dcf5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java -@@ -164,7 +164,7 @@ public class CraftFishHook extends CraftProjectile implements FishHook { - - @Override - public boolean isInOpenWater() { -- return this.getHandle().isOpenWaterFishing(); -+ return this.getHandle().outOfWaterTime < 10 && this.getHandle().calculateOpenWater(this.getHandle().blockPosition()); // Paper - isOpenWaterFishing is only calculated when a "fish" is approaching the hook - } - - @Override diff --git a/patches/server/0809-Expand-PlayerItemMendEvent.patch b/patches/server/0809-Expand-PlayerItemMendEvent.patch deleted file mode 100644 index 7c61c0095c..0000000000 --- a/patches/server/0809-Expand-PlayerItemMendEvent.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 20 Jan 2022 18:11:20 -0800 -Subject: [PATCH] Expand PlayerItemMendEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -index 3a7af27bb1ce0cbe56bd3760cd400083daf98d4c..bf0838f574fa3fb9654e087d602b8d380bd7fb28 100644 ---- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -@@ -358,7 +358,10 @@ public class ExperienceOrb extends Entity { - int j = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.serverLevel(), itemstack, amount); - int k = Math.min(j, itemstack.getDamageValue()); - // CraftBukkit start -- org.bukkit.event.player.PlayerItemMendEvent event = CraftEventFactory.callPlayerItemMendEvent(player, this, itemstack, optional.get().inSlot(), k); -+ // Paper start - mending event -+ final int consumedExperience = k > 0 ? k * amount / j : 0; -+ org.bukkit.event.player.PlayerItemMendEvent event = CraftEventFactory.callPlayerItemMendEvent(player, this, itemstack, optional.get().inSlot(), k, consumedExperience); -+ // Paper end - mending event - k = event.getRepairAmount(); - if (event.isCancelled()) { - return amount; -@@ -367,7 +370,7 @@ public class ExperienceOrb extends Entity { - - itemstack.setDamageValue(itemstack.getDamageValue() - k); - if (k > 0) { -- int l = amount - k * amount / j; -+ int l = amount - k * amount / j; // Paper - diff on change - expand PlayerMendEvents - - if (l > 0) { - // this.value = l; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls // Paper - the value field should not be mutated here because it doesn't take "count" into account -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 83e29f518a57bd2eb4113d5b93cdf47af119c715..0d2fd570463d7ad1b6457a8b14303273b97716dd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1883,11 +1883,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - handle.serverLevel(), itemstack, amount - ); - int i = Math.min(possibleDurabilityFromXp, itemstack.getDamageValue()); -- org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.get().inSlot(), i); -+ final int consumedExperience = i * amount / possibleDurabilityFromXp; // Paper - taken from ExperienceOrb#repairPlayerItems -+ org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.get().inSlot(), i, consumedExperience); - i = event.getRepairAmount(); - orb.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); - if (!event.isCancelled()) { -- amount -= i * amount / possibleDurabilityFromXp; -+ amount -= consumedExperience; // Use previously computed variable to reduce diff on change. - itemstack.setDamageValue(itemstack.getDamageValue() - i); - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index d63b9c666cf6eb1de114c5c89867b8d233267c9e..dd0d19faccbc49b5f9718e2df9f004bb17a9ef7e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1284,10 +1284,10 @@ public class CraftEventFactory { - return event; - } - -- public static PlayerItemMendEvent callPlayerItemMendEvent(net.minecraft.world.entity.player.Player entity, net.minecraft.world.entity.ExperienceOrb orb, net.minecraft.world.item.ItemStack nmsMendedItem, net.minecraft.world.entity.EquipmentSlot slot, int repairAmount) { -+ public static PlayerItemMendEvent callPlayerItemMendEvent(net.minecraft.world.entity.player.Player entity, net.minecraft.world.entity.ExperienceOrb orb, net.minecraft.world.item.ItemStack nmsMendedItem, net.minecraft.world.entity.EquipmentSlot slot, int repairAmount, int consumedExperience) { // Paper - Expand PlayerItemMendEvent - Player player = (Player) entity.getBukkitEntity(); - org.bukkit.inventory.ItemStack bukkitStack = CraftItemStack.asCraftMirror(nmsMendedItem); -- PlayerItemMendEvent event = new PlayerItemMendEvent(player, bukkitStack, CraftEquipmentSlot.getSlot(slot), (ExperienceOrb) orb.getBukkitEntity(), repairAmount); -+ PlayerItemMendEvent event = new PlayerItemMendEvent(player, bukkitStack, CraftEquipmentSlot.getSlot(slot), (ExperienceOrb) orb.getBukkitEntity(), repairAmount, consumedExperience); // Paper - Expand PlayerItemMendEvent - Bukkit.getPluginManager().callEvent(event); - return event; - } diff --git a/patches/server/0809-Refresh-ProjectileSource-for-projectiles.patch b/patches/server/0809-Refresh-ProjectileSource-for-projectiles.patch new file mode 100644 index 0000000000..eee4855e6b --- /dev/null +++ b/patches/server/0809-Refresh-ProjectileSource-for-projectiles.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 30 May 2023 12:59:10 -0700 +Subject: [PATCH] Refresh ProjectileSource for projectiles + +Makes sure the value returned by Projectile#getShooter in +the API matches the owner UUID specified in the entity nbt. +Previously, after the entity reloaded, Projectile#getShooter +would return null, while the entity still had an owner. + +Also fixes setting the shooter/owner to null actually +clearing the owner. + +Co-authored-by: Warrior <50800980+Warriorrrr@users.noreply.github.com> + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 0e52f67f0185cba47838f0a99a97b4d70314c8fa..e126f1d5117a5826c5bfec20719633d7ca5f2870 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -393,6 +393,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public boolean inWorld = false; + public boolean generation; + public int maxAirTicks = this.getDefaultMaxAirSupply(); // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() ++ @Nullable // Paper - Refresh ProjectileSource for projectiles + public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only + public boolean lastDamageCancelled; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled + public boolean persistentInvisibility = false; +diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +index df0417f27bbf0f18f007746afe24fab48e2a0a08..1a45fca020f5ecee7af837af01b60ed4590b845a 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +@@ -63,17 +63,35 @@ public abstract class Projectile extends Entity implements TraceableEntity { + this.ownerUUID = entity.getUUID(); + this.cachedOwner = entity; + } +- this.projectileSource = (entity != null && entity.getBukkitEntity() instanceof ProjectileSource) ? (ProjectileSource) entity.getBukkitEntity() : null; // CraftBukkit +- ++ // Paper start - Refresh ProjectileSource for projectiles ++ else { ++ this.ownerUUID = null; ++ this.cachedOwner = null; ++ this.projectileSource = null; ++ } ++ // Paper end - Refresh ProjectileSource for projectiles ++ this.refreshProjectileSource(false); // Paper ++ } ++ // Paper start - Refresh ProjectileSource for projectiles ++ public void refreshProjectileSource(boolean fillCache) { ++ if (fillCache) { ++ this.getOwner(); ++ } ++ if (this.cachedOwner != null && !this.cachedOwner.isRemoved() && this.projectileSource == null && this.cachedOwner.getBukkitEntity() instanceof ProjectileSource projSource) { ++ this.projectileSource = projSource; ++ } + } ++ // Paper end - Refresh ProjectileSource for projectiles + + @Nullable + @Override + public Entity getOwner() { + if (this.cachedOwner != null && !this.cachedOwner.isRemoved()) { ++ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles + return this.cachedOwner; + } else if (this.ownerUUID != null) { + this.cachedOwner = this.findOwner(this.ownerUUID); ++ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles + return this.cachedOwner; + } else { + return null; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java +index de4fb2654c7895cfd83ad694455ee56cb708c2f2..591af9d0d2fdc9953415979fc97a4a00afd85885 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java +@@ -60,6 +60,7 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti + + @Override + public final org.bukkit.projectiles.ProjectileSource getShooter() { ++ this.getHandle().refreshProjectileSource(true); // Paper - Refresh ProjectileSource for projectiles + return this.getHandle().projectileSource; + } + diff --git a/patches/server/0810-Add-transient-modifier-API.patch b/patches/server/0810-Add-transient-modifier-API.patch new file mode 100644 index 0000000000..36cc0a030a --- /dev/null +++ b/patches/server/0810-Add-transient-modifier-API.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Malfrador +Date: Wed, 31 May 2023 23:30:00 +0200 +Subject: [PATCH] Add transient modifier API + + +diff --git a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java +index 12135ffeacd648f6bc4d7d327059ea1a7e8c79c4..52439f4b959c74027eb191a3af960c70beb978e8 100644 +--- a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java ++++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java +@@ -23,6 +23,11 @@ public class UnmodifiableAttributeInstance extends CraftAttributeInstance { + throw new UnsupportedOperationException("Cannot modify default attributes"); + } + ++ @Override ++ public void addTransientModifier(AttributeModifier modifier) { ++ throw new UnsupportedOperationException("Cannot modify default attributes"); ++ } ++ + @Override + public void removeModifier(AttributeModifier modifier) { + throw new UnsupportedOperationException("Cannot modify default attributes"); +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java +index 3b171a08bd0bedfe224905feb5838d2540199bce..cd6a492f56b3dee5985c068e20009b6c833e143b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java +@@ -51,6 +51,14 @@ public class CraftAttributeInstance implements AttributeInstance { + this.handle.addPermanentModifier(CraftAttributeInstance.convert(modifier)); + } + ++ // Paper start - Transient modifier API ++ @Override ++ public void addTransientModifier(AttributeModifier modifier) { ++ Preconditions.checkArgument(modifier != null, "modifier"); ++ this.handle.addTransientModifier(CraftAttributeInstance.convert(modifier)); ++ } ++ // Paper end ++ + @Override + public void removeModifier(AttributeModifier modifier) { + Preconditions.checkArgument(modifier != null, "modifier"); diff --git a/patches/server/0810-Refresh-ProjectileSource-for-projectiles.patch b/patches/server/0810-Refresh-ProjectileSource-for-projectiles.patch deleted file mode 100644 index eee4855e6b..0000000000 --- a/patches/server/0810-Refresh-ProjectileSource-for-projectiles.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 30 May 2023 12:59:10 -0700 -Subject: [PATCH] Refresh ProjectileSource for projectiles - -Makes sure the value returned by Projectile#getShooter in -the API matches the owner UUID specified in the entity nbt. -Previously, after the entity reloaded, Projectile#getShooter -would return null, while the entity still had an owner. - -Also fixes setting the shooter/owner to null actually -clearing the owner. - -Co-authored-by: Warrior <50800980+Warriorrrr@users.noreply.github.com> - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0e52f67f0185cba47838f0a99a97b4d70314c8fa..e126f1d5117a5826c5bfec20719633d7ca5f2870 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -393,6 +393,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public boolean inWorld = false; - public boolean generation; - public int maxAirTicks = this.getDefaultMaxAirSupply(); // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() -+ @Nullable // Paper - Refresh ProjectileSource for projectiles - public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only - public boolean lastDamageCancelled; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled - public boolean persistentInvisibility = false; -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index df0417f27bbf0f18f007746afe24fab48e2a0a08..1a45fca020f5ecee7af837af01b60ed4590b845a 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -63,17 +63,35 @@ public abstract class Projectile extends Entity implements TraceableEntity { - this.ownerUUID = entity.getUUID(); - this.cachedOwner = entity; - } -- this.projectileSource = (entity != null && entity.getBukkitEntity() instanceof ProjectileSource) ? (ProjectileSource) entity.getBukkitEntity() : null; // CraftBukkit -- -+ // Paper start - Refresh ProjectileSource for projectiles -+ else { -+ this.ownerUUID = null; -+ this.cachedOwner = null; -+ this.projectileSource = null; -+ } -+ // Paper end - Refresh ProjectileSource for projectiles -+ this.refreshProjectileSource(false); // Paper -+ } -+ // Paper start - Refresh ProjectileSource for projectiles -+ public void refreshProjectileSource(boolean fillCache) { -+ if (fillCache) { -+ this.getOwner(); -+ } -+ if (this.cachedOwner != null && !this.cachedOwner.isRemoved() && this.projectileSource == null && this.cachedOwner.getBukkitEntity() instanceof ProjectileSource projSource) { -+ this.projectileSource = projSource; -+ } - } -+ // Paper end - Refresh ProjectileSource for projectiles - - @Nullable - @Override - public Entity getOwner() { - if (this.cachedOwner != null && !this.cachedOwner.isRemoved()) { -+ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles - return this.cachedOwner; - } else if (this.ownerUUID != null) { - this.cachedOwner = this.findOwner(this.ownerUUID); -+ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles - return this.cachedOwner; - } else { - return null; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java -index de4fb2654c7895cfd83ad694455ee56cb708c2f2..591af9d0d2fdc9953415979fc97a4a00afd85885 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java -@@ -60,6 +60,7 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti - - @Override - public final org.bukkit.projectiles.ProjectileSource getShooter() { -+ this.getHandle().refreshProjectileSource(true); // Paper - Refresh ProjectileSource for projectiles - return this.getHandle().projectileSource; - } - diff --git a/patches/server/0811-Add-transient-modifier-API.patch b/patches/server/0811-Add-transient-modifier-API.patch deleted file mode 100644 index 36cc0a030a..0000000000 --- a/patches/server/0811-Add-transient-modifier-API.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Malfrador -Date: Wed, 31 May 2023 23:30:00 +0200 -Subject: [PATCH] Add transient modifier API - - -diff --git a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -index 12135ffeacd648f6bc4d7d327059ea1a7e8c79c4..52439f4b959c74027eb191a3af960c70beb978e8 100644 ---- a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -+++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -@@ -23,6 +23,11 @@ public class UnmodifiableAttributeInstance extends CraftAttributeInstance { - throw new UnsupportedOperationException("Cannot modify default attributes"); - } - -+ @Override -+ public void addTransientModifier(AttributeModifier modifier) { -+ throw new UnsupportedOperationException("Cannot modify default attributes"); -+ } -+ - @Override - public void removeModifier(AttributeModifier modifier) { - throw new UnsupportedOperationException("Cannot modify default attributes"); -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -index 3b171a08bd0bedfe224905feb5838d2540199bce..cd6a492f56b3dee5985c068e20009b6c833e143b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -@@ -51,6 +51,14 @@ public class CraftAttributeInstance implements AttributeInstance { - this.handle.addPermanentModifier(CraftAttributeInstance.convert(modifier)); - } - -+ // Paper start - Transient modifier API -+ @Override -+ public void addTransientModifier(AttributeModifier modifier) { -+ Preconditions.checkArgument(modifier != null, "modifier"); -+ this.handle.addTransientModifier(CraftAttributeInstance.convert(modifier)); -+ } -+ // Paper end -+ - @Override - public void removeModifier(AttributeModifier modifier) { - Preconditions.checkArgument(modifier != null, "modifier"); diff --git a/patches/server/0811-Fix-block-place-logic.patch b/patches/server/0811-Fix-block-place-logic.patch new file mode 100644 index 0000000000..4f22f03cab --- /dev/null +++ b/patches/server/0811-Fix-block-place-logic.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Mon, 3 Apr 2023 18:46:49 +0200 +Subject: [PATCH] Fix block place logic + +Fix several issues when a player interact with a block: +* the place sound isn't played for the dispensed shulker block +* desync of the jukebox blocks between bukkit handler and the vanilla interaction +* poi can desync when the BlockPhysicsEvent is cancelled + +diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java +index 44cc12a3338b5f0448c88192c8674cd36531db34..d59120f0304823361cc4112f5583323945df4229 100644 +--- a/src/main/java/net/minecraft/world/item/BlockItem.java ++++ b/src/main/java/net/minecraft/world/item/BlockItem.java +@@ -122,7 +122,7 @@ public class BlockItem extends Item { + + SoundType soundeffecttype = iblockdata1.getSoundType(); + +- // world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), SoundCategory.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); ++ if (entityhuman == null) world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), net.minecraft.sounds.SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); // Paper - Fix block place logic; reintroduce this for the dispenser (i.e the shulker) + world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(entityhuman, iblockdata1)); + itemstack.consume(1, entityhuman); + return InteractionResult.SUCCESS; +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index f0c2187a92de633a1d4cc7e71ff62cbe30ce8774..18c011c1943867dbc4abee338b03b9be499876dd 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -550,17 +550,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + // CraftBukkit start + iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam + CraftWorld world = ((ServerLevel) this).getWorld(); ++ boolean cancelledUpdates = false; // Paper - Fix block place logic + if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper - BlockPhysicsEvent + BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata)); + this.getCraftServer().getPluginManager().callEvent(event); + +- if (event.isCancelled()) { +- return; +- } ++ cancelledUpdates = event.isCancelled(); // Paper - Fix block place logic + } + // CraftBukkit end ++ if (!cancelledUpdates) { // Paper - Fix block place logic + iblockdata.updateNeighbourShapes(this, blockposition, k, j - 1); + iblockdata.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); ++ } // Paper - Fix block place logic + } + + // CraftBukkit start - SPIGOT-5710 diff --git a/patches/server/0812-Fix-block-place-logic.patch b/patches/server/0812-Fix-block-place-logic.patch deleted file mode 100644 index 6f5dfc260e..0000000000 --- a/patches/server/0812-Fix-block-place-logic.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Mon, 3 Apr 2023 18:46:49 +0200 -Subject: [PATCH] Fix block place logic - -Fix several issues when a player interact with a block: -* the place sound isn't played for the dispensed shulker block -* desync of the jukebox blocks between bukkit handler and the vanilla interaction -* poi can desync when the BlockPhysicsEvent is cancelled - -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 44cc12a3338b5f0448c88192c8674cd36531db34..d59120f0304823361cc4112f5583323945df4229 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -122,7 +122,7 @@ public class BlockItem extends Item { - - SoundType soundeffecttype = iblockdata1.getSoundType(); - -- // world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), SoundCategory.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); -+ if (entityhuman == null) world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), net.minecraft.sounds.SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); // Paper - Fix block place logic; reintroduce this for the dispenser (i.e the shulker) - world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(entityhuman, iblockdata1)); - itemstack.consume(1, entityhuman); - return InteractionResult.SUCCESS; -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index a6f538372830f3f80740ef503733736e0561d1bd..d048d0e4b16459b5bad44ebfa3c6a8f336f6762b 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -552,17 +552,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // CraftBukkit start - iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam - CraftWorld world = ((ServerLevel) this).getWorld(); -+ boolean cancelledUpdates = false; // Paper - Fix block place logic - if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper - BlockPhysicsEvent - BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata)); - this.getCraftServer().getPluginManager().callEvent(event); - -- if (event.isCancelled()) { -- return; -- } -+ cancelledUpdates = event.isCancelled(); // Paper - Fix block place logic - } - // CraftBukkit end -+ if (!cancelledUpdates) { // Paper - Fix block place logic - iblockdata.updateNeighbourShapes(this, blockposition, k, j - 1); - iblockdata.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); -+ } // Paper - Fix block place logic - } - - // CraftBukkit start - SPIGOT-5710 diff --git a/patches/server/0812-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch b/patches/server/0812-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch new file mode 100644 index 0000000000..69e6a10e57 --- /dev/null +++ b/patches/server/0812-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Thu, 8 Jun 2023 20:23:13 -0400 +Subject: [PATCH] Fix spigot sound playing for BlockItem ItemStacks + + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 90a55f00c36903d52630c51bf69322973a2b5274..1b7d797dac1ff7ee945cf4ef8c6861475a31903d 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -577,7 +577,11 @@ public final class ItemStack implements DataComponentHolder { + + // SPIGOT-1288 - play sound stripped from ItemBlock + if (this.item instanceof BlockItem) { +- SoundType soundeffecttype = ((BlockItem) this.item).getBlock().defaultBlockState().getSoundType(); // TODO: not strictly correct, however currently only affects decorated pots ++ // Paper start - Fix spigot sound playing for BlockItem ItemStacks ++ BlockPos position = new net.minecraft.world.item.context.BlockPlaceContext(context).getClickedPos(); ++ net.minecraft.world.level.block.state.BlockState blockData = world.getBlockState(position); ++ SoundType soundeffecttype = blockData.getSoundType(); ++ // Paper end - Fix spigot sound playing for BlockItem ItemStacks + world.playSound(entityhuman, blockposition, soundeffecttype.getPlaceSound(), SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); + } + diff --git a/patches/server/0813-Call-BlockGrowEvent-for-missing-blocks.patch b/patches/server/0813-Call-BlockGrowEvent-for-missing-blocks.patch new file mode 100644 index 0000000000..d48638c261 --- /dev/null +++ b/patches/server/0813-Call-BlockGrowEvent-for-missing-blocks.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Fri, 9 Jun 2023 13:04:42 +0200 +Subject: [PATCH] Call BlockGrowEvent for missing blocks + +Call the event for pitcher crops and sniffer egg + +diff --git a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java +index ea6135edc76c06b7cd55930b620dfb05f939e4f6..640e439524cc1e5960ba99f8bd555c7dee8edbf5 100644 +--- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java +@@ -142,7 +142,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl + int i = Math.min(state.getValue(AGE) + amount, 4); + if (this.canGrow(world, pos, state, i)) { + BlockState blockState = state.setValue(AGE, Integer.valueOf(i)); +- world.setBlock(pos, blockState, 2); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, blockState, 2)) return; // Paper + if (isDouble(i)) { + world.setBlock(pos.above(), blockState.setValue(HALF, DoubleBlockHalf.UPPER), 3); + } +diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java +index 2df28caefff893f319924ae5fd376c8aeb0a2158..c6b7cfd78bc0c4cb64eada507876c293541890f4 100644 +--- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java +@@ -72,8 +72,13 @@ public class SnifferEggBlock extends Block { + @Override + public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { + if (!this.isReadyToHatch(state)) { ++ // Paper start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2)) { ++ this.rescheduleTick(world, pos); ++ return; ++ } ++ // Paper end + world.playSound(null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); +- world.setBlock(pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2); + } else { + // Paper start - Call BlockFadeEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, state.getFluidState().createLegacyBlock()).isCancelled()) { diff --git a/patches/server/0813-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch b/patches/server/0813-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch deleted file mode 100644 index 69e6a10e57..0000000000 --- a/patches/server/0813-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Thu, 8 Jun 2023 20:23:13 -0400 -Subject: [PATCH] Fix spigot sound playing for BlockItem ItemStacks - - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 90a55f00c36903d52630c51bf69322973a2b5274..1b7d797dac1ff7ee945cf4ef8c6861475a31903d 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -577,7 +577,11 @@ public final class ItemStack implements DataComponentHolder { - - // SPIGOT-1288 - play sound stripped from ItemBlock - if (this.item instanceof BlockItem) { -- SoundType soundeffecttype = ((BlockItem) this.item).getBlock().defaultBlockState().getSoundType(); // TODO: not strictly correct, however currently only affects decorated pots -+ // Paper start - Fix spigot sound playing for BlockItem ItemStacks -+ BlockPos position = new net.minecraft.world.item.context.BlockPlaceContext(context).getClickedPos(); -+ net.minecraft.world.level.block.state.BlockState blockData = world.getBlockState(position); -+ SoundType soundeffecttype = blockData.getSoundType(); -+ // Paper end - Fix spigot sound playing for BlockItem ItemStacks - world.playSound(entityhuman, blockposition, soundeffecttype.getPlaceSound(), SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); - } - diff --git a/patches/server/0814-Call-BlockGrowEvent-for-missing-blocks.patch b/patches/server/0814-Call-BlockGrowEvent-for-missing-blocks.patch deleted file mode 100644 index d48638c261..0000000000 --- a/patches/server/0814-Call-BlockGrowEvent-for-missing-blocks.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Fri, 9 Jun 2023 13:04:42 +0200 -Subject: [PATCH] Call BlockGrowEvent for missing blocks - -Call the event for pitcher crops and sniffer egg - -diff --git a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -index ea6135edc76c06b7cd55930b620dfb05f939e4f6..640e439524cc1e5960ba99f8bd555c7dee8edbf5 100644 ---- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -@@ -142,7 +142,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl - int i = Math.min(state.getValue(AGE) + amount, 4); - if (this.canGrow(world, pos, state, i)) { - BlockState blockState = state.setValue(AGE, Integer.valueOf(i)); -- world.setBlock(pos, blockState, 2); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, blockState, 2)) return; // Paper - if (isDouble(i)) { - world.setBlock(pos.above(), blockState.setValue(HALF, DoubleBlockHalf.UPPER), 3); - } -diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -index 2df28caefff893f319924ae5fd376c8aeb0a2158..c6b7cfd78bc0c4cb64eada507876c293541890f4 100644 ---- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -@@ -72,8 +72,13 @@ public class SnifferEggBlock extends Block { - @Override - public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { - if (!this.isReadyToHatch(state)) { -+ // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2)) { -+ this.rescheduleTick(world, pos); -+ return; -+ } -+ // Paper end - world.playSound(null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); -- world.setBlock(pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2); - } else { - // Paper start - Call BlockFadeEvent - if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, state.getFluidState().createLegacyBlock()).isCancelled()) { diff --git a/patches/server/0814-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch b/patches/server/0814-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch new file mode 100644 index 0000000000..4cc150197b --- /dev/null +++ b/patches/server/0814-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TheMeinerLP +Date: Tue, 13 Jun 2023 16:10:59 +0200 +Subject: [PATCH] Don't enforce icanhasbukkit default if alias block exists + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index b84dc11212aba4c06375cdbefa91c09d86a2b957..a7b79c9ec51f037287fad609c29b240e2071f2f8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -358,7 +358,11 @@ public final class CraftServer implements Server { + } + this.commandsConfiguration = YamlConfiguration.loadConfiguration(this.getCommandsConfigFile()); + this.commandsConfiguration.options().copyDefaults(true); +- this.commandsConfiguration.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("configurations/commands.yml"), Charsets.UTF_8))); ++ // Paper start - don't enforce icanhasbukkit default if alias block exists ++ final YamlConfiguration commandsDefaults = YamlConfiguration.loadConfiguration(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("configurations/commands.yml"), Charsets.UTF_8)); ++ if (this.commandsConfiguration.contains("aliases")) commandsDefaults.set("aliases", null); ++ this.commandsConfiguration.setDefaults(commandsDefaults); ++ // Paper end - don't enforce icanhasbukkit default if alias block exists + this.saveCommandsConfig(); + + // Migrate aliases from old file and add previously implicit $1- to pass all arguments diff --git a/patches/server/0815-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch b/patches/server/0815-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch deleted file mode 100644 index 761e3cb98f..0000000000 --- a/patches/server/0815-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TheMeinerLP -Date: Tue, 13 Jun 2023 16:10:59 +0200 -Subject: [PATCH] Don't enforce icanhasbukkit default if alias block exists - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index ff7bd67f593bbaabb5eb4c2b845acb2d428f1670..1310bdd5ced5941b2ab4ed1f15365722c0b8252d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -358,7 +358,11 @@ public final class CraftServer implements Server { - } - this.commandsConfiguration = YamlConfiguration.loadConfiguration(this.getCommandsConfigFile()); - this.commandsConfiguration.options().copyDefaults(true); -- this.commandsConfiguration.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("configurations/commands.yml"), Charsets.UTF_8))); -+ // Paper start - don't enforce icanhasbukkit default if alias block exists -+ final YamlConfiguration commandsDefaults = YamlConfiguration.loadConfiguration(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("configurations/commands.yml"), Charsets.UTF_8)); -+ if (this.commandsConfiguration.contains("aliases")) commandsDefaults.set("aliases", null); -+ this.commandsConfiguration.setDefaults(commandsDefaults); -+ // Paper end - don't enforce icanhasbukkit default if alias block exists - this.saveCommandsConfig(); - - // Migrate aliases from old file and add previously implicit $1- to pass all arguments diff --git a/patches/server/0815-fix-MapLike-spam-for-missing-key-selector.patch b/patches/server/0815-fix-MapLike-spam-for-missing-key-selector.patch new file mode 100644 index 0000000000..2bd3b889f1 --- /dev/null +++ b/patches/server/0815-fix-MapLike-spam-for-missing-key-selector.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 14 Jun 2023 13:17:40 -0700 +Subject: [PATCH] fix MapLike spam for missing key 'selector' + + +diff --git a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java +index 8c8c16ce53f5bdf88274cb80767decf0a2612637..0efe935e1f0a25bff95cdb849117b222ae8c603e 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java +@@ -353,7 +353,7 @@ public interface VibrationSystem { + public static Codec CODEC = RecordCodecBuilder.create((instance) -> { + return instance.group(VibrationInfo.CODEC.lenientOptionalFieldOf("event").forGetter((vibrationsystem_a) -> { + return Optional.ofNullable(vibrationsystem_a.currentVibration); +- }), VibrationSelector.CODEC.fieldOf("selector").forGetter(VibrationSystem.Data::getSelectionStrategy), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks)).apply(instance, (optional, vibrationselector, integer) -> { ++ }), VibrationSelector.CODEC.optionalFieldOf("selector").xmap(o -> o.orElseGet(VibrationSelector::new), Optional::of).forGetter(VibrationSystem.Data::getSelectionStrategy), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks)).apply(instance, (optional, vibrationselector, integer) -> { // Paper - fix MapLike spam for missing "selector" in 1.19.2 + return new VibrationSystem.Data((VibrationInfo) optional.orElse(null), vibrationselector, integer, true); // CraftBukkit - decompile error + }); + }); diff --git a/patches/server/0816-Fix-sniffer-removeExploredLocation.patch b/patches/server/0816-Fix-sniffer-removeExploredLocation.patch new file mode 100644 index 0000000000..e8b1703090 --- /dev/null +++ b/patches/server/0816-Fix-sniffer-removeExploredLocation.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sun, 11 Jun 2023 19:02:46 +0200 +Subject: [PATCH] Fix sniffer removeExploredLocation + +Add support to remove explored location in different world + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java +index 60251107371ef876d29fc9aa578835250715c4bc..555337018fe218ac5a296a5e6a1d82720fee05e1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java +@@ -34,12 +34,13 @@ public class CraftSniffer extends CraftAnimals implements Sniffer { + @Override + public void removeExploredLocation(Location location) { + Preconditions.checkArgument(location != null, "location cannot be null"); +- if (location.getWorld() != this.getWorld()) { +- return; +- } + + BlockPos blockPosition = CraftLocation.toBlockPosition(location); +- this.getHandle().getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, this.getHandle().getExploredPositions().filter(blockPositionExplored -> !blockPositionExplored.equals(blockPosition)).collect(Collectors.toList())); ++ // Paper start ++ net.minecraft.world.level.Level level = location.getWorld() != null ? ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle() : this.getHandle().level(); ++ net.minecraft.core.GlobalPos globalPos = net.minecraft.core.GlobalPos.of(level.dimension(), blockPosition); ++ this.getHandle().getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, this.getHandle().getExploredPositions().filter(blockPositionExplored -> !blockPositionExplored.equals(globalPos)).collect(Collectors.toList())); ++ // Paper end + } + + @Override diff --git a/patches/server/0816-fix-MapLike-spam-for-missing-key-selector.patch b/patches/server/0816-fix-MapLike-spam-for-missing-key-selector.patch deleted file mode 100644 index 2bd3b889f1..0000000000 --- a/patches/server/0816-fix-MapLike-spam-for-missing-key-selector.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 14 Jun 2023 13:17:40 -0700 -Subject: [PATCH] fix MapLike spam for missing key 'selector' - - -diff --git a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java -index 8c8c16ce53f5bdf88274cb80767decf0a2612637..0efe935e1f0a25bff95cdb849117b222ae8c603e 100644 ---- a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java -+++ b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java -@@ -353,7 +353,7 @@ public interface VibrationSystem { - public static Codec CODEC = RecordCodecBuilder.create((instance) -> { - return instance.group(VibrationInfo.CODEC.lenientOptionalFieldOf("event").forGetter((vibrationsystem_a) -> { - return Optional.ofNullable(vibrationsystem_a.currentVibration); -- }), VibrationSelector.CODEC.fieldOf("selector").forGetter(VibrationSystem.Data::getSelectionStrategy), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks)).apply(instance, (optional, vibrationselector, integer) -> { -+ }), VibrationSelector.CODEC.optionalFieldOf("selector").xmap(o -> o.orElseGet(VibrationSelector::new), Optional::of).forGetter(VibrationSystem.Data::getSelectionStrategy), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks)).apply(instance, (optional, vibrationselector, integer) -> { // Paper - fix MapLike spam for missing "selector" in 1.19.2 - return new VibrationSystem.Data((VibrationInfo) optional.orElse(null), vibrationselector, integer, true); // CraftBukkit - decompile error - }); - }); diff --git a/patches/server/0817-Add-method-to-remove-all-active-potion-effects.patch b/patches/server/0817-Add-method-to-remove-all-active-potion-effects.patch new file mode 100644 index 0000000000..e730bcf1d4 --- /dev/null +++ b/patches/server/0817-Add-method-to-remove-all-active-potion-effects.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 17 Jun 2023 13:17:25 -0700 +Subject: [PATCH] Add method to remove all active potion effects + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 203e06fdff824ba67dce0e026f7ea5b746d7f258..a62d17b72c675120b447e625cb3dc437681bdf20 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -573,6 +573,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + return effects; + } + ++ // Paper start - LivingEntity#clearActivePotionEffects(); ++ @Override ++ public boolean clearActivePotionEffects() { ++ return this.getHandle().removeAllEffects(EntityPotionEffectEvent.Cause.PLUGIN); ++ } ++ // Paper end ++ + @Override + public T launchProjectile(Class projectile) { + return this.launchProjectile(projectile, null); diff --git a/patches/server/0817-Fix-sniffer-removeExploredLocation.patch b/patches/server/0817-Fix-sniffer-removeExploredLocation.patch deleted file mode 100644 index e8b1703090..0000000000 --- a/patches/server/0817-Fix-sniffer-removeExploredLocation.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Sun, 11 Jun 2023 19:02:46 +0200 -Subject: [PATCH] Fix sniffer removeExploredLocation - -Add support to remove explored location in different world - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java -index 60251107371ef876d29fc9aa578835250715c4bc..555337018fe218ac5a296a5e6a1d82720fee05e1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java -@@ -34,12 +34,13 @@ public class CraftSniffer extends CraftAnimals implements Sniffer { - @Override - public void removeExploredLocation(Location location) { - Preconditions.checkArgument(location != null, "location cannot be null"); -- if (location.getWorld() != this.getWorld()) { -- return; -- } - - BlockPos blockPosition = CraftLocation.toBlockPosition(location); -- this.getHandle().getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, this.getHandle().getExploredPositions().filter(blockPositionExplored -> !blockPositionExplored.equals(blockPosition)).collect(Collectors.toList())); -+ // Paper start -+ net.minecraft.world.level.Level level = location.getWorld() != null ? ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle() : this.getHandle().level(); -+ net.minecraft.core.GlobalPos globalPos = net.minecraft.core.GlobalPos.of(level.dimension(), blockPosition); -+ this.getHandle().getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, this.getHandle().getExploredPositions().filter(blockPositionExplored -> !blockPositionExplored.equals(globalPos)).collect(Collectors.toList())); -+ // Paper end - } - - @Override diff --git a/patches/server/0818-Add-event-for-player-editing-sign.patch b/patches/server/0818-Add-event-for-player-editing-sign.patch new file mode 100644 index 0000000000..5029597839 --- /dev/null +++ b/patches/server/0818-Add-event-for-player-editing-sign.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: by77er +Date: Mon, 12 Jun 2023 12:56:46 -0400 +Subject: [PATCH] Add event for player editing sign + + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 1b7d797dac1ff7ee945cf4ef8c6861475a31903d..f81b3e050f21ce10ea86892d9a6bee9a42561514 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -556,7 +556,7 @@ public final class ItemStack implements DataComponentHolder { + try { + if (world.getBlockEntity(SignItem.openSign) instanceof SignBlockEntity tileentitysign) { + if (world.getBlockState(SignItem.openSign).getBlock() instanceof SignBlock blocksign) { +- blocksign.openTextEdit(entityhuman, tileentitysign, true, org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE); // Craftbukkit ++ blocksign.openTextEdit(entityhuman, tileentitysign, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // Craftbukkit // Paper - Add PlayerOpenSignEvent + } + } + } finally { +diff --git a/src/main/java/net/minecraft/world/level/block/SignBlock.java b/src/main/java/net/minecraft/world/level/block/SignBlock.java +index 725a207f80651939c1d793f8aa4ba27e8e4da568..b212fe323f048dab40c0ccbb9327c9fc73b9e03a 100644 +--- a/src/main/java/net/minecraft/world/level/block/SignBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/SignBlock.java +@@ -140,7 +140,7 @@ public abstract class SignBlock extends BaseEntityBlock implements SimpleWaterlo + } else if (flag1) { + return InteractionResult.SUCCESS_SERVER; + } else if (!this.otherPlayerIsEditingSign(player, tileentitysign) && player.mayBuild() && this.hasEditableText(player, tileentitysign, flag)) { +- this.openTextEdit(player, tileentitysign, flag, org.bukkit.event.player.PlayerSignOpenEvent.Cause.INTERACT); // CraftBukkit ++ this.openTextEdit(player, tileentitysign, flag, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.INTERACT); // Paper - Add PlayerOpenSignEvent + return InteractionResult.SUCCESS_SERVER; + } else { + return InteractionResult.PASS; +@@ -185,16 +185,33 @@ public abstract class SignBlock extends BaseEntityBlock implements SimpleWaterlo + return blockpropertywood; + } + ++ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - Add PlayerOpenSignEvent + public void openTextEdit(Player player, SignBlockEntity blockEntity, boolean front) { +- // Craftbukkit start +- this.openTextEdit(player, blockEntity, front, org.bukkit.event.player.PlayerSignOpenEvent.Cause.UNKNOWN); +- } +- +- public void openTextEdit(Player entityhuman, SignBlockEntity tileentitysign, boolean flag, org.bukkit.event.player.PlayerSignOpenEvent.Cause cause) { +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(entityhuman, tileentitysign, flag, cause)) { ++ // Paper start - Add PlayerOpenSignEvent ++ this.openTextEdit(player, blockEntity, front, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.UNKNOWN); ++ } ++ public void openTextEdit(Player entityhuman, SignBlockEntity tileentitysign, boolean flag, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause cause) { ++ org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) entityhuman.getBukkitEntity(); ++ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(tileentitysign.getLevel(), tileentitysign.getBlockPos()); ++ org.bukkit.craftbukkit.block.CraftSign bukkitSign = (org.bukkit.craftbukkit.block.CraftSign) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(bukkitBlock); ++ io.papermc.paper.event.player.PlayerOpenSignEvent event = new io.papermc.paper.event.player.PlayerOpenSignEvent( ++ bukkitPlayer, ++ bukkitSign, ++ flag ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK, ++ cause); ++ if (!event.callEvent()) return; ++ if (org.bukkit.event.player.PlayerSignOpenEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ final org.bukkit.event.player.PlayerSignOpenEvent.Cause legacyCause = switch (cause) { ++ case PLACE -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE; ++ case PLUGIN -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLUGIN; ++ case INTERACT -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.INTERACT; ++ case UNKNOWN -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.UNKNOWN; ++ }; ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(entityhuman, tileentitysign, flag, legacyCause)) { ++ // Paper end - Add PlayerOpenSignEvent + return; + } +- // Craftbukkit end ++ } // Paper - Add PlayerOpenSignEvent + tileentitysign.setAllowedPlayerEditor(entityhuman.getUUID()); + entityhuman.openTextEdit(tileentitysign, flag); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java +index a12702cdf36c75572e661b5b5758270f5058c181..8303343ecca91076839f4436d6b3a3bf4739c2fd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java +@@ -168,9 +168,15 @@ public class CraftSign extends CraftBlockEntityState< + Preconditions.checkArgument(sign.isPlaced(), "Sign must be placed"); + Preconditions.checkArgument(sign.getWorld() == player.getWorld(), "Sign must be in same world as Player"); + ++ // Paper start - Add PlayerOpenSignEvent ++ io.papermc.paper.event.player.PlayerOpenSignEvent event = new io.papermc.paper.event.player.PlayerOpenSignEvent((Player) player, sign, side, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLUGIN); ++ if (!event.callEvent()) return; ++ if (PlayerSignOpenEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ // Paper end - Add PlayerOpenSignEvent + if (!CraftEventFactory.callPlayerSignOpenEvent(player, sign, side, PlayerSignOpenEvent.Cause.PLUGIN)) { + return; + } ++ } // Paper - Add PlayerOpenSignEvent + + SignBlockEntity handle = ((CraftSign) sign).getTileEntity(); + handle.setAllowedPlayerEditor(player.getUniqueId()); diff --git a/patches/server/0818-Add-method-to-remove-all-active-potion-effects.patch b/patches/server/0818-Add-method-to-remove-all-active-potion-effects.patch deleted file mode 100644 index e730bcf1d4..0000000000 --- a/patches/server/0818-Add-method-to-remove-all-active-potion-effects.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 17 Jun 2023 13:17:25 -0700 -Subject: [PATCH] Add method to remove all active potion effects - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 203e06fdff824ba67dce0e026f7ea5b746d7f258..a62d17b72c675120b447e625cb3dc437681bdf20 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -573,6 +573,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - return effects; - } - -+ // Paper start - LivingEntity#clearActivePotionEffects(); -+ @Override -+ public boolean clearActivePotionEffects() { -+ return this.getHandle().removeAllEffects(EntityPotionEffectEvent.Cause.PLUGIN); -+ } -+ // Paper end -+ - @Override - public T launchProjectile(Class projectile) { - return this.launchProjectile(projectile, null); diff --git a/patches/server/0819-Add-event-for-player-editing-sign.patch b/patches/server/0819-Add-event-for-player-editing-sign.patch deleted file mode 100644 index 5029597839..0000000000 --- a/patches/server/0819-Add-event-for-player-editing-sign.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: by77er -Date: Mon, 12 Jun 2023 12:56:46 -0400 -Subject: [PATCH] Add event for player editing sign - - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 1b7d797dac1ff7ee945cf4ef8c6861475a31903d..f81b3e050f21ce10ea86892d9a6bee9a42561514 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -556,7 +556,7 @@ public final class ItemStack implements DataComponentHolder { - try { - if (world.getBlockEntity(SignItem.openSign) instanceof SignBlockEntity tileentitysign) { - if (world.getBlockState(SignItem.openSign).getBlock() instanceof SignBlock blocksign) { -- blocksign.openTextEdit(entityhuman, tileentitysign, true, org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE); // Craftbukkit -+ blocksign.openTextEdit(entityhuman, tileentitysign, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // Craftbukkit // Paper - Add PlayerOpenSignEvent - } - } - } finally { -diff --git a/src/main/java/net/minecraft/world/level/block/SignBlock.java b/src/main/java/net/minecraft/world/level/block/SignBlock.java -index 725a207f80651939c1d793f8aa4ba27e8e4da568..b212fe323f048dab40c0ccbb9327c9fc73b9e03a 100644 ---- a/src/main/java/net/minecraft/world/level/block/SignBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SignBlock.java -@@ -140,7 +140,7 @@ public abstract class SignBlock extends BaseEntityBlock implements SimpleWaterlo - } else if (flag1) { - return InteractionResult.SUCCESS_SERVER; - } else if (!this.otherPlayerIsEditingSign(player, tileentitysign) && player.mayBuild() && this.hasEditableText(player, tileentitysign, flag)) { -- this.openTextEdit(player, tileentitysign, flag, org.bukkit.event.player.PlayerSignOpenEvent.Cause.INTERACT); // CraftBukkit -+ this.openTextEdit(player, tileentitysign, flag, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.INTERACT); // Paper - Add PlayerOpenSignEvent - return InteractionResult.SUCCESS_SERVER; - } else { - return InteractionResult.PASS; -@@ -185,16 +185,33 @@ public abstract class SignBlock extends BaseEntityBlock implements SimpleWaterlo - return blockpropertywood; - } - -+ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - Add PlayerOpenSignEvent - public void openTextEdit(Player player, SignBlockEntity blockEntity, boolean front) { -- // Craftbukkit start -- this.openTextEdit(player, blockEntity, front, org.bukkit.event.player.PlayerSignOpenEvent.Cause.UNKNOWN); -- } -- -- public void openTextEdit(Player entityhuman, SignBlockEntity tileentitysign, boolean flag, org.bukkit.event.player.PlayerSignOpenEvent.Cause cause) { -- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(entityhuman, tileentitysign, flag, cause)) { -+ // Paper start - Add PlayerOpenSignEvent -+ this.openTextEdit(player, blockEntity, front, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.UNKNOWN); -+ } -+ public void openTextEdit(Player entityhuman, SignBlockEntity tileentitysign, boolean flag, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause cause) { -+ org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) entityhuman.getBukkitEntity(); -+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(tileentitysign.getLevel(), tileentitysign.getBlockPos()); -+ org.bukkit.craftbukkit.block.CraftSign bukkitSign = (org.bukkit.craftbukkit.block.CraftSign) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(bukkitBlock); -+ io.papermc.paper.event.player.PlayerOpenSignEvent event = new io.papermc.paper.event.player.PlayerOpenSignEvent( -+ bukkitPlayer, -+ bukkitSign, -+ flag ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK, -+ cause); -+ if (!event.callEvent()) return; -+ if (org.bukkit.event.player.PlayerSignOpenEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ final org.bukkit.event.player.PlayerSignOpenEvent.Cause legacyCause = switch (cause) { -+ case PLACE -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE; -+ case PLUGIN -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLUGIN; -+ case INTERACT -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.INTERACT; -+ case UNKNOWN -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.UNKNOWN; -+ }; -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(entityhuman, tileentitysign, flag, legacyCause)) { -+ // Paper end - Add PlayerOpenSignEvent - return; - } -- // Craftbukkit end -+ } // Paper - Add PlayerOpenSignEvent - tileentitysign.setAllowedPlayerEditor(entityhuman.getUUID()); - entityhuman.openTextEdit(tileentitysign, flag); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java -index a12702cdf36c75572e661b5b5758270f5058c181..8303343ecca91076839f4436d6b3a3bf4739c2fd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java -@@ -168,9 +168,15 @@ public class CraftSign extends CraftBlockEntityState< - Preconditions.checkArgument(sign.isPlaced(), "Sign must be placed"); - Preconditions.checkArgument(sign.getWorld() == player.getWorld(), "Sign must be in same world as Player"); - -+ // Paper start - Add PlayerOpenSignEvent -+ io.papermc.paper.event.player.PlayerOpenSignEvent event = new io.papermc.paper.event.player.PlayerOpenSignEvent((Player) player, sign, side, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLUGIN); -+ if (!event.callEvent()) return; -+ if (PlayerSignOpenEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ // Paper end - Add PlayerOpenSignEvent - if (!CraftEventFactory.callPlayerSignOpenEvent(player, sign, side, PlayerSignOpenEvent.Cause.PLUGIN)) { - return; - } -+ } // Paper - Add PlayerOpenSignEvent - - SignBlockEntity handle = ((CraftSign) sign).getTileEntity(); - handle.setAllowedPlayerEditor(player.getUniqueId()); diff --git a/patches/server/0819-Only-tick-item-frames-if-players-can-see-it.patch b/patches/server/0819-Only-tick-item-frames-if-players-can-see-it.patch new file mode 100644 index 0000000000..c7c6cd499f --- /dev/null +++ b/patches/server/0819-Only-tick-item-frames-if-players-can-see-it.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Redned +Date: Mon, 19 Jun 2023 15:45:53 -0500 +Subject: [PATCH] Only tick item frames if players can see it + +In the event that an item frame cannot be seen by any players, ticking the item frame every tick is unnecessary. This can be a very hot section of the entity tracker when lots of item frames are present on a server, so this reduces the logic which speeds it up. + +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index bc0f1aa61e68d2a8638d89c10bc5c71922d057f9..3cdcc4f44608d24550f2a8c6f3f5ce675d7777c5 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -116,7 +116,7 @@ public class ServerEntity { + + Entity entity = this.entity; + +- if (entity instanceof ItemFrame entityitemframe) { ++ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame entityitemframe) { // Paper - Perf: Only tick item frames if players can see it + if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block + ItemStack itemstack = entityitemframe.getItem(); + diff --git a/patches/server/0820-Fix-cmd-permission-levels-for-command-blocks.patch b/patches/server/0820-Fix-cmd-permission-levels-for-command-blocks.patch new file mode 100644 index 0000000000..aa96a27db6 --- /dev/null +++ b/patches/server/0820-Fix-cmd-permission-levels-for-command-blocks.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 24 Jan 2022 15:32:02 -0800 +Subject: [PATCH] Fix cmd permission levels for command blocks + + +diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java +index f31c5d665678c3163ed4469f8e9d395b890c1bbe..fc0c60b22844ed010aede2fa125b9fa440d3de80 100644 +--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java ++++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java +@@ -206,10 +206,29 @@ public class CommandSourceStack implements ExecutionCommandSource= level; + } + ++ // Paper start - Fix permission levels for command blocks ++ private boolean forceRespectPermissionLevel() { ++ return this.source == CommandSource.NULL || (this.source instanceof final net.minecraft.world.level.BaseCommandBlock commandBlock && commandBlock.getLevel().paperConfig().commandBlocks.forceFollowPermLevel); ++ } ++ // Paper end - Fix permission levels for command blocks ++ + // CraftBukkit start + public boolean hasPermission(int i, String bukkitPermission) { +- // World is null when loading functions +- return ((this.getLevel() == null || !this.getLevel().getCraftServer().ignoreVanillaPermissions) && this.permissionLevel >= i) || this.getBukkitSender().hasPermission(bukkitPermission); ++ // Paper start - Fix permission levels for command blocks ++ final java.util.function.BooleanSupplier hasBukkitPerm = () -> this.source == CommandSource.NULL /*treat NULL as having all bukkit perms*/ || this.getBukkitSender().hasPermission(bukkitPermission); // lazily check bukkit perms to the benefit of custom permission setups ++ // if the server is null, we must check the vanilla perm level system ++ // if ignoreVanillaPermissions is true, we can skip vanilla perms and just run the bukkit perm check ++ //noinspection ConstantValue ++ if (this.getServer() == null || !this.getServer().server.ignoreVanillaPermissions) { // server & level are null for command function loading ++ final boolean hasPermLevel = this.permissionLevel >= i; ++ if (this.forceRespectPermissionLevel()) { // NULL CommandSource and command blocks (if setting is enabled) should always pass the vanilla perm check ++ return hasPermLevel && hasBukkitPerm.getAsBoolean(); ++ } else { // otherwise check vanilla perm first then bukkit perm, matching upstream behavior ++ return hasPermLevel || hasBukkitPerm.getAsBoolean(); ++ } ++ } ++ return hasBukkitPerm.getAsBoolean(); ++ // Paper end - Fix permission levels for command blocks + } + // CraftBukkit end + +diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java +index fd12046fab797fd845ad8521f94147480dfba5da..fe9f638db3525893beed565ef9b7ac2fc76318bd 100644 +--- a/src/main/java/net/minecraft/commands/Commands.java ++++ b/src/main/java/net/minecraft/commands/Commands.java +@@ -300,16 +300,7 @@ public class Commands { + String[] args = command.split(" "); + if (args.length == 0) return; // Paper - empty commands shall not be dispatched + +- String cmd = args[0]; +- if (cmd.startsWith("minecraft:")) cmd = cmd.substring("minecraft:".length()); +- if (cmd.startsWith("bukkit:")) cmd = cmd.substring("bukkit:".length()); +- +- // Block disallowed commands +- if (cmd.equalsIgnoreCase("stop") || cmd.equalsIgnoreCase("kick") || cmd.equalsIgnoreCase("op") +- || cmd.equalsIgnoreCase("deop") || cmd.equalsIgnoreCase("ban") || cmd.equalsIgnoreCase("ban-ip") +- || cmd.equalsIgnoreCase("pardon") || cmd.equalsIgnoreCase("pardon-ip") || cmd.equalsIgnoreCase("reload")) { +- return; +- } ++ // Paper - Fix permission levels for command blocks + + // Handle vanilla commands; + if (sender.getLevel().getCraftServer().getCommandBlockOverride(args[0])) { +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java +index d7321275cf963ba4fd838226c7f705ea0f2e1ac6..56bae8ea1e7b115e85a701209f3badbd29912b28 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java +@@ -133,7 +133,7 @@ public class MinecartCommandBlock extends AbstractMinecart { + + @Override + public CommandSourceStack createCommandSourceStack() { +- return new CommandSourceStack(this, MinecartCommandBlock.this.position(), MinecartCommandBlock.this.getRotationVector(), this.getLevel(), 2, this.getName().getString(), MinecartCommandBlock.this.getDisplayName(), this.getLevel().getServer(), MinecartCommandBlock.this); ++ return new CommandSourceStack(this, MinecartCommandBlock.this.position(), MinecartCommandBlock.this.getRotationVector(), this.getLevel(), this.getLevel().paperConfig().commandBlocks.permissionsLevel, this.getName().getString(), MinecartCommandBlock.this.getDisplayName(), this.getLevel().getServer(), MinecartCommandBlock.this); // Paper - configurable command block perm level + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java +index faa0a3248217fb27dae5b918099f8a63eee6f586..a02c5feb8f2ffe6bb6070650a45762476e1ff9ac 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java +@@ -58,7 +58,7 @@ public class CommandBlockEntity extends BlockEntity { + public CommandSourceStack createCommandSourceStack() { + Direction enumdirection = (Direction) CommandBlockEntity.this.getBlockState().getValue(CommandBlock.FACING); + +- return new CommandSourceStack(this, Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, enumdirection.toYRot()), this.getLevel(), 2, this.getName().getString(), this.getName(), this.getLevel().getServer(), (Entity) null); ++ return new CommandSourceStack(this, Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, enumdirection.toYRot()), this.getLevel(), this.getLevel().paperConfig().commandBlocks.permissionsLevel, this.getName().getString(), this.getName(), this.getLevel().getServer(), (Entity) null); // Paper - configurable command block perm level + } + + @Override diff --git a/patches/server/0820-Only-tick-item-frames-if-players-can-see-it.patch b/patches/server/0820-Only-tick-item-frames-if-players-can-see-it.patch deleted file mode 100644 index c7c6cd499f..0000000000 --- a/patches/server/0820-Only-tick-item-frames-if-players-can-see-it.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Redned -Date: Mon, 19 Jun 2023 15:45:53 -0500 -Subject: [PATCH] Only tick item frames if players can see it - -In the event that an item frame cannot be seen by any players, ticking the item frame every tick is unnecessary. This can be a very hot section of the entity tracker when lots of item frames are present on a server, so this reduces the logic which speeds it up. - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index bc0f1aa61e68d2a8638d89c10bc5c71922d057f9..3cdcc4f44608d24550f2a8c6f3f5ce675d7777c5 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -116,7 +116,7 @@ public class ServerEntity { - - Entity entity = this.entity; - -- if (entity instanceof ItemFrame entityitemframe) { -+ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame entityitemframe) { // Paper - Perf: Only tick item frames if players can see it - if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block - ItemStack itemstack = entityitemframe.getItem(); - diff --git a/patches/server/0821-Add-option-to-disable-block-updates.patch b/patches/server/0821-Add-option-to-disable-block-updates.patch new file mode 100644 index 0000000000..0ea835ecc9 --- /dev/null +++ b/patches/server/0821-Add-option-to-disable-block-updates.patch @@ -0,0 +1,179 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Boy +Date: Sun, 18 Jun 2023 17:45:33 +0200 +Subject: [PATCH] Add option to disable block updates + + +diff --git a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java +index bf2790fae091ab9d7f4ec4b2ab0f103190c31984..5d3ca961b325a39efcd6b398a27f9a4d300b35e5 100644 +--- a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java +@@ -38,6 +38,7 @@ public class ChorusPlantBlock extends PipeBlock { + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates + return getStateWithConnections(ctx.getLevel(), ctx.getClickedPos(), this.defaultBlockState()); + } + +@@ -68,6 +69,7 @@ public class ChorusPlantBlock extends PipeBlock { + BlockState neighborState, + RandomSource random + ) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return state; // Paper - add option to disable block updates + if (!state.canSurvive(world, pos)) { + tickView.scheduleTick(pos, this, 1); + return super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); +@@ -79,6 +81,7 @@ public class ChorusPlantBlock extends PipeBlock { + + @Override + protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return; // Paper - add option to disable block updates + if (!state.canSurvive(world, pos)) { + world.destroyBlock(pos, true); + } +@@ -86,6 +89,7 @@ public class ChorusPlantBlock extends PipeBlock { + + @Override + protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return true; // Paper - add option to disable block updates + BlockState blockState = world.getBlockState(pos.below()); + boolean bl = !world.getBlockState(pos.above()).isAir() && !blockState.isAir(); + +diff --git a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java +index 0e0441646bd21a14a8bea576e5400ce937ebea01..437ad7051bad2d7dccc1a9ae764bdc5dcbe88612 100644 +--- a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java +@@ -45,6 +45,7 @@ public class HugeMushroomBlock extends Block { + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates + BlockGetter blockGetter = ctx.getLevel(); + BlockPos blockPos = ctx.getClickedPos(); + return this.defaultBlockState() +@@ -67,6 +68,7 @@ public class HugeMushroomBlock extends Block { + BlockState neighborState, + RandomSource random + ) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates + return neighborState.is(this) + ? state.setValue(PROPERTY_BY_DIRECTION.get(direction), Boolean.valueOf(false)) + : super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); +@@ -74,6 +76,7 @@ public class HugeMushroomBlock extends Block { + + @Override + protected BlockState rotate(BlockState state, Rotation rotation) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates + return state.setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.NORTH)), state.getValue(NORTH)) + .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.SOUTH)), state.getValue(SOUTH)) + .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.EAST)), state.getValue(EAST)) +@@ -84,6 +87,7 @@ public class HugeMushroomBlock extends Block { + + @Override + protected BlockState mirror(BlockState state, Mirror mirror) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates + return state.setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.NORTH)), state.getValue(NORTH)) + .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.SOUTH)), state.getValue(SOUTH)) + .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.EAST)), state.getValue(EAST)) +diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java +index 71fd7a467a4cb89cad8d2541366fd4add9115e04..6582db84c5307257f16c321453491cf24e40c9c7 100644 +--- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java +@@ -68,11 +68,13 @@ public class NoteBlock extends Block { + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return this.defaultBlockState(); // Paper - place without considering instrument + return this.setInstrument(ctx.getLevel(), ctx.getClickedPos(), this.defaultBlockState()); + } + + @Override + protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return state; // Paper - prevent noteblock instrument from updating + boolean flag = direction.getAxis() == Direction.Axis.Y; + + return flag ? this.setInstrument(world, pos, state) : super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); +@@ -80,6 +82,7 @@ public class NoteBlock extends Block { + + @Override + protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, @Nullable Orientation wireOrientation, boolean notify) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return; // Paper - prevent noteblock powered-state from updating + boolean flag1 = world.hasNeighborSignal(pos); + + if (flag1 != (Boolean) state.getValue(NoteBlock.POWERED)) { +@@ -116,7 +119,7 @@ public class NoteBlock extends Block { + @Override + protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { + if (!world.isClientSide) { +- state = (BlockState) state.cycle(NoteBlock.NOTE); ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) state = (BlockState) state.cycle(NoteBlock.NOTE); // Paper - prevent noteblock note from updating + world.setBlock(pos, state, 3); + this.playNote(player, state, world, pos); + player.awardStat(Stats.TUNE_NOTEBLOCK); +diff --git a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java +index f079e5a9aa098225acf09ed9b4aa7ddbc2381270..74cce7874809dcbce2718ec3840bb6bb3127e871 100644 +--- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java +@@ -68,6 +68,7 @@ public class TripWireBlock extends Block { + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return this.defaultBlockState(); // Paper - place tripwire without updating + Level world = ctx.getLevel(); + BlockPos blockposition = ctx.getClickedPos(); + +@@ -76,11 +77,13 @@ public class TripWireBlock extends Block { + + @Override + protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return state; // Paper - prevent tripwire from updating + return direction.getAxis().isHorizontal() ? (BlockState) state.setValue((Property) TripWireBlock.PROPERTY_BY_DIRECTION.get(direction), this.shouldConnectTo(neighborState, direction)) : super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); + } + + @Override + protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating + if (!oldState.is(state.getBlock())) { + this.updateSource(world, pos, state); + } +@@ -88,6 +91,7 @@ public class TripWireBlock extends Block { + + @Override + protected void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating + if (!moved && !state.is(newState.getBlock())) { + this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true)); + } +@@ -95,6 +99,7 @@ public class TripWireBlock extends Block { + + @Override + public BlockState playerWillDestroy(Level world, BlockPos pos, BlockState state, Player player) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return state; // Paper - prevent disarming tripwires + if (!world.isClientSide && !player.getMainHandItem().isEmpty() && player.getMainHandItem().is(Items.SHEARS)) { + world.setBlock(pos, (BlockState) state.setValue(TripWireBlock.DISARMED, true), 4); + world.gameEvent((Entity) player, (Holder) GameEvent.SHEAR, pos); +@@ -104,6 +109,7 @@ public class TripWireBlock extends Block { + } + + private void updateSource(Level world, BlockPos pos, BlockState state) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating + Direction[] aenumdirection = new Direction[]{Direction.SOUTH, Direction.WEST}; + int i = aenumdirection.length; + int j = 0; +@@ -141,6 +147,7 @@ public class TripWireBlock extends Block { + + @Override + protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwires from detecting collision + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + if (!world.isClientSide) { + if (!(Boolean) state.getValue(TripWireBlock.POWERED)) { +@@ -151,6 +158,7 @@ public class TripWireBlock extends Block { + + @Override + protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwire pressed check + if ((Boolean) world.getBlockState(pos).getValue(TripWireBlock.POWERED)) { + this.checkPressed(world, pos); + } diff --git a/patches/server/0821-Fix-cmd-permission-levels-for-command-blocks.patch b/patches/server/0821-Fix-cmd-permission-levels-for-command-blocks.patch deleted file mode 100644 index aa96a27db6..0000000000 --- a/patches/server/0821-Fix-cmd-permission-levels-for-command-blocks.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 24 Jan 2022 15:32:02 -0800 -Subject: [PATCH] Fix cmd permission levels for command blocks - - -diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index f31c5d665678c3163ed4469f8e9d395b890c1bbe..fc0c60b22844ed010aede2fa125b9fa440d3de80 100644 ---- a/src/main/java/net/minecraft/commands/CommandSourceStack.java -+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -206,10 +206,29 @@ public class CommandSourceStack implements ExecutionCommandSource= level; - } - -+ // Paper start - Fix permission levels for command blocks -+ private boolean forceRespectPermissionLevel() { -+ return this.source == CommandSource.NULL || (this.source instanceof final net.minecraft.world.level.BaseCommandBlock commandBlock && commandBlock.getLevel().paperConfig().commandBlocks.forceFollowPermLevel); -+ } -+ // Paper end - Fix permission levels for command blocks -+ - // CraftBukkit start - public boolean hasPermission(int i, String bukkitPermission) { -- // World is null when loading functions -- return ((this.getLevel() == null || !this.getLevel().getCraftServer().ignoreVanillaPermissions) && this.permissionLevel >= i) || this.getBukkitSender().hasPermission(bukkitPermission); -+ // Paper start - Fix permission levels for command blocks -+ final java.util.function.BooleanSupplier hasBukkitPerm = () -> this.source == CommandSource.NULL /*treat NULL as having all bukkit perms*/ || this.getBukkitSender().hasPermission(bukkitPermission); // lazily check bukkit perms to the benefit of custom permission setups -+ // if the server is null, we must check the vanilla perm level system -+ // if ignoreVanillaPermissions is true, we can skip vanilla perms and just run the bukkit perm check -+ //noinspection ConstantValue -+ if (this.getServer() == null || !this.getServer().server.ignoreVanillaPermissions) { // server & level are null for command function loading -+ final boolean hasPermLevel = this.permissionLevel >= i; -+ if (this.forceRespectPermissionLevel()) { // NULL CommandSource and command blocks (if setting is enabled) should always pass the vanilla perm check -+ return hasPermLevel && hasBukkitPerm.getAsBoolean(); -+ } else { // otherwise check vanilla perm first then bukkit perm, matching upstream behavior -+ return hasPermLevel || hasBukkitPerm.getAsBoolean(); -+ } -+ } -+ return hasBukkitPerm.getAsBoolean(); -+ // Paper end - Fix permission levels for command blocks - } - // CraftBukkit end - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index fd12046fab797fd845ad8521f94147480dfba5da..fe9f638db3525893beed565ef9b7ac2fc76318bd 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -300,16 +300,7 @@ public class Commands { - String[] args = command.split(" "); - if (args.length == 0) return; // Paper - empty commands shall not be dispatched - -- String cmd = args[0]; -- if (cmd.startsWith("minecraft:")) cmd = cmd.substring("minecraft:".length()); -- if (cmd.startsWith("bukkit:")) cmd = cmd.substring("bukkit:".length()); -- -- // Block disallowed commands -- if (cmd.equalsIgnoreCase("stop") || cmd.equalsIgnoreCase("kick") || cmd.equalsIgnoreCase("op") -- || cmd.equalsIgnoreCase("deop") || cmd.equalsIgnoreCase("ban") || cmd.equalsIgnoreCase("ban-ip") -- || cmd.equalsIgnoreCase("pardon") || cmd.equalsIgnoreCase("pardon-ip") || cmd.equalsIgnoreCase("reload")) { -- return; -- } -+ // Paper - Fix permission levels for command blocks - - // Handle vanilla commands; - if (sender.getLevel().getCraftServer().getCommandBlockOverride(args[0])) { -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -index d7321275cf963ba4fd838226c7f705ea0f2e1ac6..56bae8ea1e7b115e85a701209f3badbd29912b28 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -@@ -133,7 +133,7 @@ public class MinecartCommandBlock extends AbstractMinecart { - - @Override - public CommandSourceStack createCommandSourceStack() { -- return new CommandSourceStack(this, MinecartCommandBlock.this.position(), MinecartCommandBlock.this.getRotationVector(), this.getLevel(), 2, this.getName().getString(), MinecartCommandBlock.this.getDisplayName(), this.getLevel().getServer(), MinecartCommandBlock.this); -+ return new CommandSourceStack(this, MinecartCommandBlock.this.position(), MinecartCommandBlock.this.getRotationVector(), this.getLevel(), this.getLevel().paperConfig().commandBlocks.permissionsLevel, this.getName().getString(), MinecartCommandBlock.this.getDisplayName(), this.getLevel().getServer(), MinecartCommandBlock.this); // Paper - configurable command block perm level - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java -index faa0a3248217fb27dae5b918099f8a63eee6f586..a02c5feb8f2ffe6bb6070650a45762476e1ff9ac 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java -@@ -58,7 +58,7 @@ public class CommandBlockEntity extends BlockEntity { - public CommandSourceStack createCommandSourceStack() { - Direction enumdirection = (Direction) CommandBlockEntity.this.getBlockState().getValue(CommandBlock.FACING); - -- return new CommandSourceStack(this, Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, enumdirection.toYRot()), this.getLevel(), 2, this.getName().getString(), this.getName(), this.getLevel().getServer(), (Entity) null); -+ return new CommandSourceStack(this, Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, enumdirection.toYRot()), this.getLevel(), this.getLevel().paperConfig().commandBlocks.permissionsLevel, this.getName().getString(), this.getName(), this.getLevel().getServer(), (Entity) null); // Paper - configurable command block perm level - } - - @Override diff --git a/patches/server/0822-Add-option-to-disable-block-updates.patch b/patches/server/0822-Add-option-to-disable-block-updates.patch deleted file mode 100644 index 0ea835ecc9..0000000000 --- a/patches/server/0822-Add-option-to-disable-block-updates.patch +++ /dev/null @@ -1,179 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Boy -Date: Sun, 18 Jun 2023 17:45:33 +0200 -Subject: [PATCH] Add option to disable block updates - - -diff --git a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java -index bf2790fae091ab9d7f4ec4b2ab0f103190c31984..5d3ca961b325a39efcd6b398a27f9a4d300b35e5 100644 ---- a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java -@@ -38,6 +38,7 @@ public class ChorusPlantBlock extends PipeBlock { - - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates - return getStateWithConnections(ctx.getLevel(), ctx.getClickedPos(), this.defaultBlockState()); - } - -@@ -68,6 +69,7 @@ public class ChorusPlantBlock extends PipeBlock { - BlockState neighborState, - RandomSource random - ) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return state; // Paper - add option to disable block updates - if (!state.canSurvive(world, pos)) { - tickView.scheduleTick(pos, this, 1); - return super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); -@@ -79,6 +81,7 @@ public class ChorusPlantBlock extends PipeBlock { - - @Override - protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return; // Paper - add option to disable block updates - if (!state.canSurvive(world, pos)) { - world.destroyBlock(pos, true); - } -@@ -86,6 +89,7 @@ public class ChorusPlantBlock extends PipeBlock { - - @Override - protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return true; // Paper - add option to disable block updates - BlockState blockState = world.getBlockState(pos.below()); - boolean bl = !world.getBlockState(pos.above()).isAir() && !blockState.isAir(); - -diff --git a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java -index 0e0441646bd21a14a8bea576e5400ce937ebea01..437ad7051bad2d7dccc1a9ae764bdc5dcbe88612 100644 ---- a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java -@@ -45,6 +45,7 @@ public class HugeMushroomBlock extends Block { - - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates - BlockGetter blockGetter = ctx.getLevel(); - BlockPos blockPos = ctx.getClickedPos(); - return this.defaultBlockState() -@@ -67,6 +68,7 @@ public class HugeMushroomBlock extends Block { - BlockState neighborState, - RandomSource random - ) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates - return neighborState.is(this) - ? state.setValue(PROPERTY_BY_DIRECTION.get(direction), Boolean.valueOf(false)) - : super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); -@@ -74,6 +76,7 @@ public class HugeMushroomBlock extends Block { - - @Override - protected BlockState rotate(BlockState state, Rotation rotation) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates - return state.setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.NORTH)), state.getValue(NORTH)) - .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.SOUTH)), state.getValue(SOUTH)) - .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.EAST)), state.getValue(EAST)) -@@ -84,6 +87,7 @@ public class HugeMushroomBlock extends Block { - - @Override - protected BlockState mirror(BlockState state, Mirror mirror) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates - return state.setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.NORTH)), state.getValue(NORTH)) - .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.SOUTH)), state.getValue(SOUTH)) - .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.EAST)), state.getValue(EAST)) -diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -index 71fd7a467a4cb89cad8d2541366fd4add9115e04..6582db84c5307257f16c321453491cf24e40c9c7 100644 ---- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -@@ -68,11 +68,13 @@ public class NoteBlock extends Block { - - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return this.defaultBlockState(); // Paper - place without considering instrument - return this.setInstrument(ctx.getLevel(), ctx.getClickedPos(), this.defaultBlockState()); - } - - @Override - protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return state; // Paper - prevent noteblock instrument from updating - boolean flag = direction.getAxis() == Direction.Axis.Y; - - return flag ? this.setInstrument(world, pos, state) : super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); -@@ -80,6 +82,7 @@ public class NoteBlock extends Block { - - @Override - protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, @Nullable Orientation wireOrientation, boolean notify) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return; // Paper - prevent noteblock powered-state from updating - boolean flag1 = world.hasNeighborSignal(pos); - - if (flag1 != (Boolean) state.getValue(NoteBlock.POWERED)) { -@@ -116,7 +119,7 @@ public class NoteBlock extends Block { - @Override - protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { - if (!world.isClientSide) { -- state = (BlockState) state.cycle(NoteBlock.NOTE); -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) state = (BlockState) state.cycle(NoteBlock.NOTE); // Paper - prevent noteblock note from updating - world.setBlock(pos, state, 3); - this.playNote(player, state, world, pos); - player.awardStat(Stats.TUNE_NOTEBLOCK); -diff --git a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java -index f079e5a9aa098225acf09ed9b4aa7ddbc2381270..74cce7874809dcbce2718ec3840bb6bb3127e871 100644 ---- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java -@@ -68,6 +68,7 @@ public class TripWireBlock extends Block { - - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return this.defaultBlockState(); // Paper - place tripwire without updating - Level world = ctx.getLevel(); - BlockPos blockposition = ctx.getClickedPos(); - -@@ -76,11 +77,13 @@ public class TripWireBlock extends Block { - - @Override - protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return state; // Paper - prevent tripwire from updating - return direction.getAxis().isHorizontal() ? (BlockState) state.setValue((Property) TripWireBlock.PROPERTY_BY_DIRECTION.get(direction), this.shouldConnectTo(neighborState, direction)) : super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); - } - - @Override - protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating - if (!oldState.is(state.getBlock())) { - this.updateSource(world, pos, state); - } -@@ -88,6 +91,7 @@ public class TripWireBlock extends Block { - - @Override - protected void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating - if (!moved && !state.is(newState.getBlock())) { - this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true)); - } -@@ -95,6 +99,7 @@ public class TripWireBlock extends Block { - - @Override - public BlockState playerWillDestroy(Level world, BlockPos pos, BlockState state, Player player) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return state; // Paper - prevent disarming tripwires - if (!world.isClientSide && !player.getMainHandItem().isEmpty() && player.getMainHandItem().is(Items.SHEARS)) { - world.setBlock(pos, (BlockState) state.setValue(TripWireBlock.DISARMED, true), 4); - world.gameEvent((Entity) player, (Holder) GameEvent.SHEAR, pos); -@@ -104,6 +109,7 @@ public class TripWireBlock extends Block { - } - - private void updateSource(Level world, BlockPos pos, BlockState state) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating - Direction[] aenumdirection = new Direction[]{Direction.SOUTH, Direction.WEST}; - int i = aenumdirection.length; - int j = 0; -@@ -141,6 +147,7 @@ public class TripWireBlock extends Block { - - @Override - protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwires from detecting collision - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (!world.isClientSide) { - if (!(Boolean) state.getValue(TripWireBlock.POWERED)) { -@@ -151,6 +158,7 @@ public class TripWireBlock extends Block { - - @Override - protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwire pressed check - if ((Boolean) world.getBlockState(pos).getValue(TripWireBlock.POWERED)) { - this.checkPressed(world, pos); - } diff --git a/patches/server/0822-Call-missing-BlockDispenseEvent.patch b/patches/server/0822-Call-missing-BlockDispenseEvent.patch new file mode 100644 index 0000000000..c8d68a1ed8 --- /dev/null +++ b/patches/server/0822-Call-missing-BlockDispenseEvent.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sat, 29 Oct 2022 15:41:56 +0200 +Subject: [PATCH] Call missing BlockDispenseEvent + + +diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +index 5793569ae8a088f21b0d8d6771a5099b1e88be09..f8f570a97789ab16e57774f233506a289277d5d9 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -768,6 +768,13 @@ public interface DispenseItemBehavior { + this.setSuccess(true); + if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) { + if ((Integer) iblockdata.getValue(RespawnAnchorBlock.CHARGE) != 4) { ++ // Paper start - Call missing BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this); ++ if (result != null) { ++ this.setSuccess(false); ++ return result; ++ } ++ // Paper end - Call missing BlockDispenseEvent + RespawnAnchorBlock.charge((Entity) null, worldserver, blockposition, iblockdata); + stack.shrink(1); + } else { +@@ -845,6 +852,13 @@ public interface DispenseItemBehavior { + Optional optional = HoneycombItem.getWaxed(iblockdata); + + if (optional.isPresent()) { ++ // Paper start - Call missing BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this); ++ if (result != null) { ++ this.setSuccess(false); ++ return result; ++ } ++ // Paper end - Call missing BlockDispenseEvent + worldserver.setBlockAndUpdate(blockposition, (BlockState) optional.get()); + worldserver.levelEvent(3003, blockposition, 0); + stack.shrink(1); +@@ -872,6 +886,12 @@ public interface DispenseItemBehavior { + if (!worldserver.getBlockState(blockposition1).is(BlockTags.CONVERTABLE_TO_MUD)) { + return this.defaultDispenseItemBehavior.dispense(pointer, stack); + } else { ++ // Paper start - Call missing BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition1, stack, this); ++ if (result != null) { ++ return result; ++ } ++ // Paper end - Call missing BlockDispenseEvent + if (!worldserver.isClientSide) { + for (int k = 0; k < 5; ++k) { + worldserver.sendParticles(ParticleTypes.SPLASH, (double) blockposition.getX() + worldserver.random.nextDouble(), (double) (blockposition.getY() + 1), (double) blockposition.getZ() + worldserver.random.nextDouble(), 1, 0.0D, 0.0D, 0.0D, 1.0D); +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index dd0d19faccbc49b5f9718e2df9f004bb17a9ef7e..38c8f69dff0abe62fc405a9fbb29c80d45aa675f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -2196,6 +2196,32 @@ public class CraftEventFactory { + } + // Paper end + ++ // Paper start - Call missing BlockDispenseEvent ++ @Nullable ++ public static ItemStack handleBlockDispenseEvent(net.minecraft.core.dispenser.BlockSource pointer, BlockPos to, ItemStack itemStack, net.minecraft.core.dispenser.DispenseItemBehavior instance) { ++ org.bukkit.block.Block bukkitBlock = CraftBlock.at(pointer.level(), pointer.pos()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1)); ++ ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to)); ++ if (!net.minecraft.world.level.block.DispenserBlock.eventFired) { ++ if (!event.callEvent()) { ++ return itemStack; ++ } ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ net.minecraft.core.dispenser.DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ if (itemBehavior != net.minecraft.core.dispenser.DispenseItemBehavior.NOOP && itemBehavior != instance) { ++ itemBehavior.dispense(pointer, eventStack); ++ return itemStack; ++ } ++ } ++ return null; ++ } ++ // Paper end - Call missing BlockDispenseEvent ++ + // Paper start - add EntityFertilizeEggEvent + /** + * Calls the {@link io.papermc.paper.event.entity.EntityFertilizeEggEvent}. diff --git a/patches/server/0823-Call-missing-BlockDispenseEvent.patch b/patches/server/0823-Call-missing-BlockDispenseEvent.patch deleted file mode 100644 index c8d68a1ed8..0000000000 --- a/patches/server/0823-Call-missing-BlockDispenseEvent.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Sat, 29 Oct 2022 15:41:56 +0200 -Subject: [PATCH] Call missing BlockDispenseEvent - - -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 5793569ae8a088f21b0d8d6771a5099b1e88be09..f8f570a97789ab16e57774f233506a289277d5d9 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -768,6 +768,13 @@ public interface DispenseItemBehavior { - this.setSuccess(true); - if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) { - if ((Integer) iblockdata.getValue(RespawnAnchorBlock.CHARGE) != 4) { -+ // Paper start - Call missing BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this); -+ if (result != null) { -+ this.setSuccess(false); -+ return result; -+ } -+ // Paper end - Call missing BlockDispenseEvent - RespawnAnchorBlock.charge((Entity) null, worldserver, blockposition, iblockdata); - stack.shrink(1); - } else { -@@ -845,6 +852,13 @@ public interface DispenseItemBehavior { - Optional optional = HoneycombItem.getWaxed(iblockdata); - - if (optional.isPresent()) { -+ // Paper start - Call missing BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this); -+ if (result != null) { -+ this.setSuccess(false); -+ return result; -+ } -+ // Paper end - Call missing BlockDispenseEvent - worldserver.setBlockAndUpdate(blockposition, (BlockState) optional.get()); - worldserver.levelEvent(3003, blockposition, 0); - stack.shrink(1); -@@ -872,6 +886,12 @@ public interface DispenseItemBehavior { - if (!worldserver.getBlockState(blockposition1).is(BlockTags.CONVERTABLE_TO_MUD)) { - return this.defaultDispenseItemBehavior.dispense(pointer, stack); - } else { -+ // Paper start - Call missing BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition1, stack, this); -+ if (result != null) { -+ return result; -+ } -+ // Paper end - Call missing BlockDispenseEvent - if (!worldserver.isClientSide) { - for (int k = 0; k < 5; ++k) { - worldserver.sendParticles(ParticleTypes.SPLASH, (double) blockposition.getX() + worldserver.random.nextDouble(), (double) (blockposition.getY() + 1), (double) blockposition.getZ() + worldserver.random.nextDouble(), 1, 0.0D, 0.0D, 0.0D, 1.0D); -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index dd0d19faccbc49b5f9718e2df9f004bb17a9ef7e..38c8f69dff0abe62fc405a9fbb29c80d45aa675f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -2196,6 +2196,32 @@ public class CraftEventFactory { - } - // Paper end - -+ // Paper start - Call missing BlockDispenseEvent -+ @Nullable -+ public static ItemStack handleBlockDispenseEvent(net.minecraft.core.dispenser.BlockSource pointer, BlockPos to, ItemStack itemStack, net.minecraft.core.dispenser.DispenseItemBehavior instance) { -+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(pointer.level(), pointer.pos()); -+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1)); -+ -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to)); -+ if (!net.minecraft.world.level.block.DispenserBlock.eventFired) { -+ if (!event.callEvent()) { -+ return itemStack; -+ } -+ } -+ -+ if (!event.getItem().equals(craftItem)) { -+ // Chain to handler for new item -+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -+ net.minecraft.core.dispenser.DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ if (itemBehavior != net.minecraft.core.dispenser.DispenseItemBehavior.NOOP && itemBehavior != instance) { -+ itemBehavior.dispense(pointer, eventStack); -+ return itemStack; -+ } -+ } -+ return null; -+ } -+ // Paper end - Call missing BlockDispenseEvent -+ - // Paper start - add EntityFertilizeEggEvent - /** - * Calls the {@link io.papermc.paper.event.entity.EntityFertilizeEggEvent}. diff --git a/patches/server/0823-Don-t-load-chunks-for-supporting-block-checks.patch b/patches/server/0823-Don-t-load-chunks-for-supporting-block-checks.patch new file mode 100644 index 0000000000..5f0cc11546 --- /dev/null +++ b/patches/server/0823-Don-t-load-chunks-for-supporting-block-checks.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Wed, 5 Jul 2023 23:11:53 +0100 +Subject: [PATCH] Don't load chunks for supporting block checks + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index e126f1d5117a5826c5bfec20719633d7ca5f2870..3444b1a2da80b85e2b1928d69ff0dd980c5fb34f 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1228,7 +1228,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + protected BlockPos getOnPos(float offset) { +- if (this.mainSupportingBlockPos.isPresent()) { ++ if (this.mainSupportingBlockPos.isPresent() && this.level().getChunkIfLoadedImmediately(this.mainSupportingBlockPos.get()) != null) { // Paper - ensure no loads + BlockPos blockposition = (BlockPos) this.mainSupportingBlockPos.get(); + + if (offset <= 1.0E-5F) { diff --git a/patches/server/0824-Don-t-load-chunks-for-supporting-block-checks.patch b/patches/server/0824-Don-t-load-chunks-for-supporting-block-checks.patch deleted file mode 100644 index 5f0cc11546..0000000000 --- a/patches/server/0824-Don-t-load-chunks-for-supporting-block-checks.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Wed, 5 Jul 2023 23:11:53 +0100 -Subject: [PATCH] Don't load chunks for supporting block checks - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index e126f1d5117a5826c5bfec20719633d7ca5f2870..3444b1a2da80b85e2b1928d69ff0dd980c5fb34f 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1228,7 +1228,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - protected BlockPos getOnPos(float offset) { -- if (this.mainSupportingBlockPos.isPresent()) { -+ if (this.mainSupportingBlockPos.isPresent() && this.level().getChunkIfLoadedImmediately(this.mainSupportingBlockPos.get()) != null) { // Paper - ensure no loads - BlockPos blockposition = (BlockPos) this.mainSupportingBlockPos.get(); - - if (offset <= 1.0E-5F) { diff --git a/patches/server/0824-Optimize-player-lookups-for-beacons.patch b/patches/server/0824-Optimize-player-lookups-for-beacons.patch new file mode 100644 index 0000000000..7e1285d891 --- /dev/null +++ b/patches/server/0824-Optimize-player-lookups-for-beacons.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Thu, 6 Jul 2023 20:17:37 -0700 +Subject: [PATCH] Optimize player lookups for beacons + +For larger ranges, it's better to iterate over the player list +than the entity slices. + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +index 2a7d896dd9a02acf6e3596e2e2e7ed50f4b88377..0e0d178f2793ab014358f534c8dc53218b89f083 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +@@ -333,7 +333,22 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10); // Paper - Custom beacon ranges + + AABB axisalignedbb = (new AABB(blockposition)).inflate(d0).expandTowards(0.0D, (double) world.getHeight(), 0.0D); +- List list = world.getEntitiesOfClass(Player.class, axisalignedbb); ++ // Paper start - Perf: optimize player lookup for beacons ++ List list; ++ if (d0 <= 128.0) { ++ list = world.getEntitiesOfClass(Player.class, axisalignedbb); ++ } else { ++ list = new java.util.ArrayList<>(); ++ for (Player player : world.players()) { ++ if (player.isSpectator()) { ++ continue; ++ } ++ if (player.getBoundingBox().intersects(axisalignedbb)) { ++ list.add(player); ++ } ++ } ++ } ++ // Paper end - Perf: optimize player lookup for beacons + + return list; + } diff --git a/patches/server/0825-More-Sign-Block-API.patch b/patches/server/0825-More-Sign-Block-API.patch new file mode 100644 index 0000000000..70558b0010 --- /dev/null +++ b/patches/server/0825-More-Sign-Block-API.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 23 Jun 2023 12:16:28 -0700 +Subject: [PATCH] More Sign Block API + +Co-authored-by: SoSeDiK + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java +index a34c2fc6ac1418a89d789b8945ca3dad57f64151..8ac19e1e052e73ff3fd09089bb8e3fd687390ee4 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java +@@ -68,12 +68,17 @@ public class SignBlockEntity extends BlockEntity { + } + + public boolean isFacingFrontText(net.minecraft.world.entity.player.Player player) { ++ // Paper start - More Sign Block API ++ return this.isFacingFrontText(player.getX(), player.getZ()); ++ } ++ public boolean isFacingFrontText(double x, double z) { ++ // Paper end - More Sign Block API + Block block = this.getBlockState().getBlock(); + + if (block instanceof SignBlock blocksign) { + Vec3 vec3d = blocksign.getSignHitboxCenterPosition(this.getBlockState()); +- double d0 = player.getX() - ((double) this.getBlockPos().getX() + vec3d.x); +- double d1 = player.getZ() - ((double) this.getBlockPos().getZ() + vec3d.z); ++ double d0 = x - ((double) this.getBlockPos().getX() + vec3d.x); // Paper - More Sign Block API ++ double d1 = z - ((double) this.getBlockPos().getZ() + vec3d.z); // Paper - More Sign Block API + float f = blocksign.getYRotationDegrees(this.getBlockState()); + float f1 = (float) (Mth.atan2(d1, d0) * 57.2957763671875D) - 90.0F; + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java +index 8303343ecca91076839f4436d6b3a3bf4739c2fd..e3c333d26dea9af9dd51e1662f81f1d472ab0233 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java +@@ -198,6 +198,26 @@ public class CraftSign extends CraftBlockEntityState< + } + // Paper end + ++ // Paper start - More Sign Block API ++ @Override ++ public java.util.UUID getAllowedEditorUniqueId() { ++ this.ensureNoWorldGeneration(); ++ return this.getTileEntity().getPlayerWhoMayEdit(); ++ } ++ ++ @Override ++ public void setAllowedEditorUniqueId(java.util.UUID uuid) { ++ this.ensureNoWorldGeneration(); ++ this.getTileEntity().setAllowedPlayerEditor(uuid); ++ } ++ ++ @Override ++ public Side getInteractableSideFor(final double x, final double z) { ++ this.requirePlaced(); ++ return this.getSnapshot().isFacingFrontText(x, z) ? Side.FRONT : Side.BACK; ++ } ++ // Paper end - More Sign Block API ++ + public static Component[] sanitizeLines(String[] lines) { + Component[] components = new Component[4]; + diff --git a/patches/server/0825-Optimize-player-lookups-for-beacons.patch b/patches/server/0825-Optimize-player-lookups-for-beacons.patch deleted file mode 100644 index 7e1285d891..0000000000 --- a/patches/server/0825-Optimize-player-lookups-for-beacons.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 6 Jul 2023 20:17:37 -0700 -Subject: [PATCH] Optimize player lookups for beacons - -For larger ranges, it's better to iterate over the player list -than the entity slices. - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index 2a7d896dd9a02acf6e3596e2e2e7ed50f4b88377..0e0d178f2793ab014358f534c8dc53218b89f083 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -333,7 +333,22 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10); // Paper - Custom beacon ranges - - AABB axisalignedbb = (new AABB(blockposition)).inflate(d0).expandTowards(0.0D, (double) world.getHeight(), 0.0D); -- List list = world.getEntitiesOfClass(Player.class, axisalignedbb); -+ // Paper start - Perf: optimize player lookup for beacons -+ List list; -+ if (d0 <= 128.0) { -+ list = world.getEntitiesOfClass(Player.class, axisalignedbb); -+ } else { -+ list = new java.util.ArrayList<>(); -+ for (Player player : world.players()) { -+ if (player.isSpectator()) { -+ continue; -+ } -+ if (player.getBoundingBox().intersects(axisalignedbb)) { -+ list.add(player); -+ } -+ } -+ } -+ // Paper end - Perf: optimize player lookup for beacons - - return list; - } diff --git a/patches/server/0826-More-Sign-Block-API.patch b/patches/server/0826-More-Sign-Block-API.patch deleted file mode 100644 index 70558b0010..0000000000 --- a/patches/server/0826-More-Sign-Block-API.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 23 Jun 2023 12:16:28 -0700 -Subject: [PATCH] More Sign Block API - -Co-authored-by: SoSeDiK - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -index a34c2fc6ac1418a89d789b8945ca3dad57f64151..8ac19e1e052e73ff3fd09089bb8e3fd687390ee4 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -@@ -68,12 +68,17 @@ public class SignBlockEntity extends BlockEntity { - } - - public boolean isFacingFrontText(net.minecraft.world.entity.player.Player player) { -+ // Paper start - More Sign Block API -+ return this.isFacingFrontText(player.getX(), player.getZ()); -+ } -+ public boolean isFacingFrontText(double x, double z) { -+ // Paper end - More Sign Block API - Block block = this.getBlockState().getBlock(); - - if (block instanceof SignBlock blocksign) { - Vec3 vec3d = blocksign.getSignHitboxCenterPosition(this.getBlockState()); -- double d0 = player.getX() - ((double) this.getBlockPos().getX() + vec3d.x); -- double d1 = player.getZ() - ((double) this.getBlockPos().getZ() + vec3d.z); -+ double d0 = x - ((double) this.getBlockPos().getX() + vec3d.x); // Paper - More Sign Block API -+ double d1 = z - ((double) this.getBlockPos().getZ() + vec3d.z); // Paper - More Sign Block API - float f = blocksign.getYRotationDegrees(this.getBlockState()); - float f1 = (float) (Mth.atan2(d1, d0) * 57.2957763671875D) - 90.0F; - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java -index 8303343ecca91076839f4436d6b3a3bf4739c2fd..e3c333d26dea9af9dd51e1662f81f1d472ab0233 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java -@@ -198,6 +198,26 @@ public class CraftSign extends CraftBlockEntityState< - } - // Paper end - -+ // Paper start - More Sign Block API -+ @Override -+ public java.util.UUID getAllowedEditorUniqueId() { -+ this.ensureNoWorldGeneration(); -+ return this.getTileEntity().getPlayerWhoMayEdit(); -+ } -+ -+ @Override -+ public void setAllowedEditorUniqueId(java.util.UUID uuid) { -+ this.ensureNoWorldGeneration(); -+ this.getTileEntity().setAllowedPlayerEditor(uuid); -+ } -+ -+ @Override -+ public Side getInteractableSideFor(final double x, final double z) { -+ this.requirePlaced(); -+ return this.getSnapshot().isFacingFrontText(x, z) ? Side.FRONT : Side.BACK; -+ } -+ // Paper end - More Sign Block API -+ - public static Component[] sanitizeLines(String[] lines) { - Component[] components = new Component[4]; - diff --git a/patches/server/0826-fix-item-meta-for-tadpole-buckets.patch b/patches/server/0826-fix-item-meta-for-tadpole-buckets.patch new file mode 100644 index 0000000000..04c4b6a873 --- /dev/null +++ b/patches/server/0826-fix-item-meta-for-tadpole-buckets.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 11 Jul 2023 11:22:30 -0700 +Subject: [PATCH] fix item meta for tadpole buckets + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java +index 4f5568707d725195ee19b65274454fec8bf99d64..d29f4dd9808e2001c79535d663ca77d6840f6092 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java +@@ -265,7 +265,7 @@ public final class CraftItemMetas { + if (itemType == ItemType.SUSPICIOUS_STEW) { + return CraftItemMetas.asType(CraftItemMetas.SUSPICIOUS_STEW_META_DATA); + } +- if (itemType == ItemType.COD_BUCKET || itemType == ItemType.PUFFERFISH_BUCKET ++ if (itemType == ItemType.COD_BUCKET || itemType == ItemType.PUFFERFISH_BUCKET || itemType == ItemType.TADPOLE_BUCKET // Paper + || itemType == ItemType.SALMON_BUCKET || itemType == ItemType.ITEM_FRAME + || itemType == ItemType.GLOW_ITEM_FRAME || itemType == ItemType.PAINTING) { + return CraftItemMetas.asType(CraftItemMetas.ENTITY_TAG_META_DATA); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +index 27af7ca9d62bdb4a24be5af139c181d7bc271ba5..3ff0340c40e9dc9a6e690de15ccade7a0c4e8f02 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +@@ -19,6 +19,7 @@ public class CraftMetaEntityTag extends CraftMetaItem { + Material.COD_BUCKET, + Material.PUFFERFISH_BUCKET, + Material.SALMON_BUCKET, ++ Material.TADPOLE_BUCKET, // Paper + Material.ITEM_FRAME, + Material.GLOW_ITEM_FRAME, + Material.PAINTING +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +index 50faaaa48dffcaf53823caed1e3f7263cd5c441f..ba5c958f322dc34baff3c9d1b99741a4ffeee135 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +@@ -209,6 +209,27 @@ public class ItemMetaTest { + } + } + ++ // Paper start - check entity tag metas ++ private static final java.util.Set> ENTITY_TAG_METAS = java.util.Set.of( ++ CraftMetaEntityTag.class, ++ CraftMetaTropicalFishBucket.class, ++ CraftMetaAxolotlBucket.class ++ ); ++ @Test ++ public void testEntityTagMeta() { ++ for (final Item item : BuiltInRegistries.ITEM) { ++ if (item instanceof net.minecraft.world.item.HangingEntityItem || item instanceof net.minecraft.world.item.MobBucketItem) { ++ ItemStack stack = new ItemStack(CraftItemType.minecraftToBukkit(item)); ++ assertTrue(ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()), "missing entity tag meta handling for " + item); ++ stack = CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.STONE); ++ stack.editMeta(meta -> meta.displayName(net.kyori.adventure.text.Component.text("hello"))); ++ stack.setType(CraftItemType.minecraftToBukkit(item)); ++ assertTrue(ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()), "missing entity tag meta handling for " + item); ++ } ++ } ++ } ++ // Paper end ++ + @Test + public void testEachExtraData() { + final List providers = Arrays.asList( diff --git a/patches/server/0827-Fix-BanList-API.patch b/patches/server/0827-Fix-BanList-API.patch new file mode 100644 index 0000000000..1164a2d949 --- /dev/null +++ b/patches/server/0827-Fix-BanList-API.patch @@ -0,0 +1,351 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 4 Jul 2023 11:27:10 -0700 +Subject: [PATCH] Fix BanList API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +index 30c1c203022c2ed777dcddfd68ef2e3752c62ea1..2c2c4db31a746b4eb853dc04c6b3e5631bbfa034 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +@@ -115,17 +115,17 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa + } + + @Override +- public BanEntry ban(String reason, Date expires, String source) { ++ public BanEntry ban(String reason, Date expires, String source) { // Paper - fix ban list API + return ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); + } + + @Override +- public BanEntry ban(String reason, Instant expires, String source) { ++ public BanEntry ban(String reason, Instant expires, String source) { // Paper - fix ban list API + return ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); + } + + @Override +- public BanEntry ban(String reason, Duration duration, String source) { ++ public BanEntry ban(String reason, Duration duration, String source) { // Paper - fix ban list API + return ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, duration, source); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java +index 13e5e44b069121e51b9486c445902937f1d6c6d8..4a37c8172b42b10472bb90c9310c7ae3eeaa3481 100644 +--- a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java ++++ b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java +@@ -9,7 +9,7 @@ import org.bukkit.BanEntry; + import org.bukkit.craftbukkit.profile.CraftPlayerProfile; + import org.bukkit.profile.PlayerProfile; + +-public final class CraftProfileBanEntry implements BanEntry { ++public final class CraftProfileBanEntry implements BanEntry { // Paper + private static final Date minorDate = Date.from(Instant.parse("1899-12-31T04:00:00Z")); + private final UserBanList list; + private final GameProfile profile; +@@ -33,8 +33,8 @@ public final class CraftProfileBanEntry implements BanEntry { + } + + @Override +- public PlayerProfile getBanTarget() { +- return new CraftPlayerProfile(this.profile); ++ public com.destroystokyo.paper.profile.PlayerProfile getBanTarget() { // Paper ++ return new com.destroystokyo.paper.profile.CraftPlayerProfile(this.profile); // Paper + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java +index 172202accf4448a933fcf1ff820316c7910dd7f7..50ee7656580d386db473c054f5c5ec57bb2b1424 100644 +--- a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java ++++ b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java +@@ -24,42 +24,80 @@ public class CraftProfileBanList implements ProfileBanList { + } + + @Override +- public BanEntry getBanEntry(String target) { ++ public BanEntry getBanEntry(String target) { // Paper + Preconditions.checkArgument(target != null, "Target cannot be null"); + + return this.getBanEntry(CraftProfileBanList.getProfile(target)); + } + + @Override +- public BanEntry getBanEntry(PlayerProfile target) { ++ public BanEntry getBanEntry(PlayerProfile target) { // Paper + Preconditions.checkArgument(target != null, "Target cannot be null"); + +- return this.getBanEntry(((CraftPlayerProfile) target).buildGameProfile()); ++ return this.getBanEntry(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile()); // Paper ++ } ++ // Paper start - fix ban list API ++ @Override ++ public BanEntry getBanEntry(final com.destroystokyo.paper.profile.PlayerProfile target) { ++ Preconditions.checkArgument(target != null, "target cannot be null"); ++ ++ return this.getBanEntry(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile()); ++ } ++ ++ @Override ++ public BanEntry addBan(final com.destroystokyo.paper.profile.PlayerProfile target, final String reason, final Date expires, final String source) { ++ Preconditions.checkArgument(target != null, "PlayerProfile cannot be null"); ++ Preconditions.checkArgument(target.getId() != null, "The PlayerProfile UUID cannot be null"); ++ ++ return this.addBan(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile(), reason, expires, source); ++ } ++ ++ @Override ++ public boolean isBanned(final com.destroystokyo.paper.profile.PlayerProfile target) { ++ return this.isBanned((com.destroystokyo.paper.profile.SharedPlayerProfile) target); ++ } ++ ++ @Override ++ public void pardon(final com.destroystokyo.paper.profile.PlayerProfile target) { ++ this.pardon((com.destroystokyo.paper.profile.SharedPlayerProfile) target); + } + + @Override +- public BanEntry addBan(String target, String reason, Date expires, String source) { ++ public BanEntry addBan(final com.destroystokyo.paper.profile.PlayerProfile target, final String reason, final Instant expires, final String source) { ++ Date date = expires != null ? Date.from(expires) : null; ++ return this.addBan(target, reason, date, source); ++ } ++ ++ @Override ++ public BanEntry addBan(final com.destroystokyo.paper.profile.PlayerProfile target, final String reason, final Duration duration, final String source) { ++ Instant instant = duration != null ? Instant.now().plus(duration) : null; ++ return this.addBan(target, reason, instant, source); ++ } ++ // Paper end - fix ban list API ++ ++ @Override ++ public BanEntry addBan(String target, String reason, Date expires, String source) { // Paper - fix ban list API + Preconditions.checkArgument(target != null, "Ban target cannot be null"); + + return this.addBan(CraftProfileBanList.getProfileByName(target), reason, expires, source); + } + + @Override +- public BanEntry addBan(PlayerProfile target, String reason, Date expires, String source) { ++ public BanEntry addBan(PlayerProfile target, String reason, Date expires, String source) { // Paper - fix ban list API + Preconditions.checkArgument(target != null, "PlayerProfile cannot be null"); + Preconditions.checkArgument(target.getUniqueId() != null, "The PlayerProfile UUID cannot be null"); + +- return this.addBan(((CraftPlayerProfile) target).buildGameProfile(), reason, expires, source); ++ return this.addBan(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile(), reason, expires, source); // Paper + } + + @Override +- public BanEntry addBan(PlayerProfile target, String reason, Instant expires, String source) { ++ public BanEntry addBan(PlayerProfile target, String reason, Instant expires, String source) { // Paper - fix ban list API + Date date = expires != null ? Date.from(expires) : null; + return this.addBan(target, reason, date, source); + } + + @Override +- public BanEntry addBan(PlayerProfile target, String reason, Duration duration, String source) { ++ public BanEntry addBan(PlayerProfile target, String reason, Duration duration, String source) { // Paper - fix ban list API + Instant instant = duration != null ? Instant.now().plus(duration) : null; + return this.addBan(target, reason, instant, source); + } +@@ -76,8 +114,8 @@ public class CraftProfileBanList implements ProfileBanList { + } + + @Override +- public Set> getEntries() { +- ImmutableSet.Builder> builder = ImmutableSet.builder(); ++ public Set> getEntries() { // Paper ++ ImmutableSet.Builder> builder = ImmutableSet.builder(); // Paper + for (UserBanListEntry entry : this.list.getEntries()) { + GameProfile profile = entry.getUser(); + builder.add(new CraftProfileBanEntry(profile, entry, this.list)); +@@ -88,9 +126,14 @@ public class CraftProfileBanList implements ProfileBanList { + + @Override + public boolean isBanned(PlayerProfile target) { ++ // Paper start ++ return this.isBanned((com.destroystokyo.paper.profile.SharedPlayerProfile) target); ++ } ++ private boolean isBanned(com.destroystokyo.paper.profile.SharedPlayerProfile target) { ++ // Paper end + Preconditions.checkArgument(target != null, "Target cannot be null"); + +- return this.isBanned(((CraftPlayerProfile) target).buildGameProfile()); ++ return this.isBanned(target.buildGameProfile()); // Paper + } + + @Override +@@ -102,9 +145,14 @@ public class CraftProfileBanList implements ProfileBanList { + + @Override + public void pardon(PlayerProfile target) { ++ // Paper start ++ this.pardon((com.destroystokyo.paper.profile.SharedPlayerProfile) target); ++ } ++ private void pardon(com.destroystokyo.paper.profile.SharedPlayerProfile target) { ++ // Paper end + Preconditions.checkArgument(target != null, "Target cannot be null"); + +- this.pardon(((CraftPlayerProfile) target).buildGameProfile()); ++ this.pardon(target.buildGameProfile()); // Paper + } + + @Override +@@ -114,7 +162,7 @@ public class CraftProfileBanList implements ProfileBanList { + this.pardon(CraftProfileBanList.getProfile(target)); + } + +- public BanEntry getBanEntry(GameProfile profile) { ++ public BanEntry getBanEntry(GameProfile profile) { // Paper + if (profile == null) { + return null; + } +@@ -127,7 +175,7 @@ public class CraftProfileBanList implements ProfileBanList { + return new CraftProfileBanEntry(profile, entry, this.list); + } + +- public BanEntry addBan(GameProfile profile, String reason, Date expires, String source) { ++ public BanEntry addBan(GameProfile profile, String reason, Date expires, String source) { // Paper + if (profile == null) { + return null; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 0d2fd570463d7ad1b6457a8b14303273b97716dd..ccf2c23ecf6f406ae07a2d7614d52e65da8ca586 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1777,23 +1777,23 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + + @Override +- public BanEntry ban(String reason, Date expires, String source) { ++ public BanEntry ban(String reason, Date expires, String source) { // Paper - fix ban list API + return this.ban(reason, expires, source, true); + } + + @Override +- public BanEntry ban(String reason, Instant expires, String source) { ++ public BanEntry ban(String reason, Instant expires, String source) { // Paper - fix ban list API + return this.ban(reason, expires != null ? Date.from(expires) : null, source); + } + + @Override +- public BanEntry ban(String reason, Duration duration, String source) { ++ public BanEntry ban(String reason, Duration duration, String source) { // Paper - fix ban list API + return this.ban(reason, duration != null ? Instant.now().plus(duration) : null, source); + } + + @Override +- public BanEntry ban(String reason, Date expires, String source, boolean kickPlayer) { +- BanEntry banEntry = ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); ++ public BanEntry ban(String reason, Date expires, String source, boolean kickPlayer) { // Paper - fix ban list API ++ BanEntry banEntry = ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); // Paper - fix ban list API + if (kickPlayer) { + this.kickPlayer(reason); + } +@@ -1801,12 +1801,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + + @Override +- public BanEntry ban(String reason, Instant instant, String source, boolean kickPlayer) { ++ public BanEntry ban(String reason, Instant instant, String source, boolean kickPlayer) { // Paper - fix ban list API + return this.ban(reason, instant != null ? Date.from(instant) : null, source, kickPlayer); + } + + @Override +- public BanEntry ban(String reason, Duration duration, String source, boolean kickPlayer) { ++ public BanEntry ban(String reason, Duration duration, String source, boolean kickPlayer) { // Paper - fix ban list API + return this.ban(reason, duration != null ? Instant.now().plus(duration) : null, source, kickPlayer); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java +index d9cc76d7e60001957c0f59fdc32d016f3589aa08..f58dec12326734c61f4bc2298a87fb38f1ac1dc4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java ++++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java +@@ -31,7 +31,7 @@ import org.bukkit.profile.PlayerTextures; + import org.jetbrains.annotations.ApiStatus; + + @SerializableAs("PlayerProfile") +-public final class CraftPlayerProfile implements PlayerProfile, com.destroystokyo.paper.profile.SharedPlayerProfile { // Paper ++public final class CraftPlayerProfile implements PlayerProfile, com.destroystokyo.paper.profile.SharedPlayerProfile, com.destroystokyo.paper.profile.PlayerProfile { // Paper + + @Nonnull + public static GameProfile validateSkullProfile(@Nonnull GameProfile gameProfile) { +@@ -162,7 +162,7 @@ public final class CraftPlayerProfile implements PlayerProfile, com.destroystoky + } + + @Override +- public CompletableFuture update() { ++ public CompletableFuture update() { // Paper - have to remove generic to avoid clashing between bukkit.PlayerProfile and paper.PlayerProfile + return CompletableFuture.supplyAsync(this::getUpdatedProfile, Util.PROFILE_EXECUTOR); // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread + } + +@@ -321,4 +321,71 @@ public final class CraftPlayerProfile implements PlayerProfile, com.destroystoky + // Paper - diff on change + return profile; + } ++ ++ // Paper start - This must implement our PlayerProfile so generic casts succeed from cb.CraftPlayerProfile to paper.PlayerProfile ++ // The methods don't actually have to be implemented, because the profile should immediately be cast to SharedPlayerProfile ++ @Override ++ public String setName(final String name) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public UUID getId() { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public UUID setId(final UUID uuid) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public java.util.Set getProperties() { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public boolean hasProperty(final String property) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public void setProperty(final com.destroystokyo.paper.profile.ProfileProperty property) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public void setProperties(final java.util.Collection properties) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public void clearProperties() { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public boolean completeFromCache() { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public boolean completeFromCache(final boolean onlineMode) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public boolean completeFromCache(final boolean lookupUUID, final boolean onlineMode) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public boolean complete(final boolean textures) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } ++ ++ @Override ++ public boolean complete(final boolean textures, final boolean onlineMode) { ++ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); ++ } + } diff --git a/patches/server/0827-fix-item-meta-for-tadpole-buckets.patch b/patches/server/0827-fix-item-meta-for-tadpole-buckets.patch deleted file mode 100644 index 04c4b6a873..0000000000 --- a/patches/server/0827-fix-item-meta-for-tadpole-buckets.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 11 Jul 2023 11:22:30 -0700 -Subject: [PATCH] fix item meta for tadpole buckets - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -index 4f5568707d725195ee19b65274454fec8bf99d64..d29f4dd9808e2001c79535d663ca77d6840f6092 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -@@ -265,7 +265,7 @@ public final class CraftItemMetas { - if (itemType == ItemType.SUSPICIOUS_STEW) { - return CraftItemMetas.asType(CraftItemMetas.SUSPICIOUS_STEW_META_DATA); - } -- if (itemType == ItemType.COD_BUCKET || itemType == ItemType.PUFFERFISH_BUCKET -+ if (itemType == ItemType.COD_BUCKET || itemType == ItemType.PUFFERFISH_BUCKET || itemType == ItemType.TADPOLE_BUCKET // Paper - || itemType == ItemType.SALMON_BUCKET || itemType == ItemType.ITEM_FRAME - || itemType == ItemType.GLOW_ITEM_FRAME || itemType == ItemType.PAINTING) { - return CraftItemMetas.asType(CraftItemMetas.ENTITY_TAG_META_DATA); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -index 27af7ca9d62bdb4a24be5af139c181d7bc271ba5..3ff0340c40e9dc9a6e690de15ccade7a0c4e8f02 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -@@ -19,6 +19,7 @@ public class CraftMetaEntityTag extends CraftMetaItem { - Material.COD_BUCKET, - Material.PUFFERFISH_BUCKET, - Material.SALMON_BUCKET, -+ Material.TADPOLE_BUCKET, // Paper - Material.ITEM_FRAME, - Material.GLOW_ITEM_FRAME, - Material.PAINTING -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java -index 50faaaa48dffcaf53823caed1e3f7263cd5c441f..ba5c958f322dc34baff3c9d1b99741a4ffeee135 100644 ---- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java -@@ -209,6 +209,27 @@ public class ItemMetaTest { - } - } - -+ // Paper start - check entity tag metas -+ private static final java.util.Set> ENTITY_TAG_METAS = java.util.Set.of( -+ CraftMetaEntityTag.class, -+ CraftMetaTropicalFishBucket.class, -+ CraftMetaAxolotlBucket.class -+ ); -+ @Test -+ public void testEntityTagMeta() { -+ for (final Item item : BuiltInRegistries.ITEM) { -+ if (item instanceof net.minecraft.world.item.HangingEntityItem || item instanceof net.minecraft.world.item.MobBucketItem) { -+ ItemStack stack = new ItemStack(CraftItemType.minecraftToBukkit(item)); -+ assertTrue(ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()), "missing entity tag meta handling for " + item); -+ stack = CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.STONE); -+ stack.editMeta(meta -> meta.displayName(net.kyori.adventure.text.Component.text("hello"))); -+ stack.setType(CraftItemType.minecraftToBukkit(item)); -+ assertTrue(ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()), "missing entity tag meta handling for " + item); -+ } -+ } -+ } -+ // Paper end -+ - @Test - public void testEachExtraData() { - final List providers = Arrays.asList( diff --git a/patches/server/0828-Determine-lava-and-water-fluid-explosion-resistance-.patch b/patches/server/0828-Determine-lava-and-water-fluid-explosion-resistance-.patch new file mode 100644 index 0000000000..4f2b8e09cd --- /dev/null +++ b/patches/server/0828-Determine-lava-and-water-fluid-explosion-resistance-.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: galacticwarrior9 +Date: Thu, 13 Jul 2023 21:32:13 +0100 +Subject: [PATCH] Determine lava and water fluid explosion resistance by their + block explosion resistance + +When selecting which explosion resistance to use for lava and water, vanilla selects the highest value between their block explosion resistance and fluid explosion resistance. + +Problems emerge when we want to reduce the explosion resistance of water or lava, since the fluid explosion resistance is hardcoded to return 100.0F and can't be changed by a plugin. This simply makes the fluid explosion resistance the same as the block explosion resistance, which allows plugin to change the value. Since both are the same in vanilla, this has no side effects on servers that do not need to do this. + +diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java +index a27ceed2cac6c16eb4e5f2959db9e482e67e9de6..884db3e64cb22ed765beec8f11ea309fcf810207 100644 +--- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java ++++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java +@@ -233,7 +233,7 @@ public abstract class LavaFluid extends FlowingFluid { + + @Override + protected float getExplosionResistance() { +- return 100.0F; ++ return Blocks.LAVA.getExplosionResistance(); // Paper - Get explosion resistance from actual block + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/material/WaterFluid.java b/src/main/java/net/minecraft/world/level/material/WaterFluid.java +index 0a7c05c08bf8c6c331b91e399dc4103a91dc20fe..552925ba47c7475e2e1ec2ded0966f28ed3e50a5 100644 +--- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java ++++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java +@@ -126,7 +126,7 @@ public abstract class WaterFluid extends FlowingFluid { + + @Override + protected float getExplosionResistance() { +- return 100.0F; ++ return Blocks.WATER.getExplosionResistance(); // Paper - Get explosion resistance from actual block + } + + @Override diff --git a/patches/server/0828-Fix-BanList-API.patch b/patches/server/0828-Fix-BanList-API.patch deleted file mode 100644 index 1164a2d949..0000000000 --- a/patches/server/0828-Fix-BanList-API.patch +++ /dev/null @@ -1,351 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 4 Jul 2023 11:27:10 -0700 -Subject: [PATCH] Fix BanList API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -index 30c1c203022c2ed777dcddfd68ef2e3752c62ea1..2c2c4db31a746b4eb853dc04c6b3e5631bbfa034 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -@@ -115,17 +115,17 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa - } - - @Override -- public BanEntry ban(String reason, Date expires, String source) { -+ public BanEntry ban(String reason, Date expires, String source) { // Paper - fix ban list API - return ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); - } - - @Override -- public BanEntry ban(String reason, Instant expires, String source) { -+ public BanEntry ban(String reason, Instant expires, String source) { // Paper - fix ban list API - return ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); - } - - @Override -- public BanEntry ban(String reason, Duration duration, String source) { -+ public BanEntry ban(String reason, Duration duration, String source) { // Paper - fix ban list API - return ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, duration, source); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java -index 13e5e44b069121e51b9486c445902937f1d6c6d8..4a37c8172b42b10472bb90c9310c7ae3eeaa3481 100644 ---- a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java -+++ b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanEntry.java -@@ -9,7 +9,7 @@ import org.bukkit.BanEntry; - import org.bukkit.craftbukkit.profile.CraftPlayerProfile; - import org.bukkit.profile.PlayerProfile; - --public final class CraftProfileBanEntry implements BanEntry { -+public final class CraftProfileBanEntry implements BanEntry { // Paper - private static final Date minorDate = Date.from(Instant.parse("1899-12-31T04:00:00Z")); - private final UserBanList list; - private final GameProfile profile; -@@ -33,8 +33,8 @@ public final class CraftProfileBanEntry implements BanEntry { - } - - @Override -- public PlayerProfile getBanTarget() { -- return new CraftPlayerProfile(this.profile); -+ public com.destroystokyo.paper.profile.PlayerProfile getBanTarget() { // Paper -+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(this.profile); // Paper - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java -index 172202accf4448a933fcf1ff820316c7910dd7f7..50ee7656580d386db473c054f5c5ec57bb2b1424 100644 ---- a/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java -+++ b/src/main/java/org/bukkit/craftbukkit/ban/CraftProfileBanList.java -@@ -24,42 +24,80 @@ public class CraftProfileBanList implements ProfileBanList { - } - - @Override -- public BanEntry getBanEntry(String target) { -+ public BanEntry getBanEntry(String target) { // Paper - Preconditions.checkArgument(target != null, "Target cannot be null"); - - return this.getBanEntry(CraftProfileBanList.getProfile(target)); - } - - @Override -- public BanEntry getBanEntry(PlayerProfile target) { -+ public BanEntry getBanEntry(PlayerProfile target) { // Paper - Preconditions.checkArgument(target != null, "Target cannot be null"); - -- return this.getBanEntry(((CraftPlayerProfile) target).buildGameProfile()); -+ return this.getBanEntry(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile()); // Paper -+ } -+ // Paper start - fix ban list API -+ @Override -+ public BanEntry getBanEntry(final com.destroystokyo.paper.profile.PlayerProfile target) { -+ Preconditions.checkArgument(target != null, "target cannot be null"); -+ -+ return this.getBanEntry(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile()); -+ } -+ -+ @Override -+ public BanEntry addBan(final com.destroystokyo.paper.profile.PlayerProfile target, final String reason, final Date expires, final String source) { -+ Preconditions.checkArgument(target != null, "PlayerProfile cannot be null"); -+ Preconditions.checkArgument(target.getId() != null, "The PlayerProfile UUID cannot be null"); -+ -+ return this.addBan(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile(), reason, expires, source); -+ } -+ -+ @Override -+ public boolean isBanned(final com.destroystokyo.paper.profile.PlayerProfile target) { -+ return this.isBanned((com.destroystokyo.paper.profile.SharedPlayerProfile) target); -+ } -+ -+ @Override -+ public void pardon(final com.destroystokyo.paper.profile.PlayerProfile target) { -+ this.pardon((com.destroystokyo.paper.profile.SharedPlayerProfile) target); - } - - @Override -- public BanEntry addBan(String target, String reason, Date expires, String source) { -+ public BanEntry addBan(final com.destroystokyo.paper.profile.PlayerProfile target, final String reason, final Instant expires, final String source) { -+ Date date = expires != null ? Date.from(expires) : null; -+ return this.addBan(target, reason, date, source); -+ } -+ -+ @Override -+ public BanEntry addBan(final com.destroystokyo.paper.profile.PlayerProfile target, final String reason, final Duration duration, final String source) { -+ Instant instant = duration != null ? Instant.now().plus(duration) : null; -+ return this.addBan(target, reason, instant, source); -+ } -+ // Paper end - fix ban list API -+ -+ @Override -+ public BanEntry addBan(String target, String reason, Date expires, String source) { // Paper - fix ban list API - Preconditions.checkArgument(target != null, "Ban target cannot be null"); - - return this.addBan(CraftProfileBanList.getProfileByName(target), reason, expires, source); - } - - @Override -- public BanEntry addBan(PlayerProfile target, String reason, Date expires, String source) { -+ public BanEntry addBan(PlayerProfile target, String reason, Date expires, String source) { // Paper - fix ban list API - Preconditions.checkArgument(target != null, "PlayerProfile cannot be null"); - Preconditions.checkArgument(target.getUniqueId() != null, "The PlayerProfile UUID cannot be null"); - -- return this.addBan(((CraftPlayerProfile) target).buildGameProfile(), reason, expires, source); -+ return this.addBan(((com.destroystokyo.paper.profile.SharedPlayerProfile) target).buildGameProfile(), reason, expires, source); // Paper - } - - @Override -- public BanEntry addBan(PlayerProfile target, String reason, Instant expires, String source) { -+ public BanEntry addBan(PlayerProfile target, String reason, Instant expires, String source) { // Paper - fix ban list API - Date date = expires != null ? Date.from(expires) : null; - return this.addBan(target, reason, date, source); - } - - @Override -- public BanEntry addBan(PlayerProfile target, String reason, Duration duration, String source) { -+ public BanEntry addBan(PlayerProfile target, String reason, Duration duration, String source) { // Paper - fix ban list API - Instant instant = duration != null ? Instant.now().plus(duration) : null; - return this.addBan(target, reason, instant, source); - } -@@ -76,8 +114,8 @@ public class CraftProfileBanList implements ProfileBanList { - } - - @Override -- public Set> getEntries() { -- ImmutableSet.Builder> builder = ImmutableSet.builder(); -+ public Set> getEntries() { // Paper -+ ImmutableSet.Builder> builder = ImmutableSet.builder(); // Paper - for (UserBanListEntry entry : this.list.getEntries()) { - GameProfile profile = entry.getUser(); - builder.add(new CraftProfileBanEntry(profile, entry, this.list)); -@@ -88,9 +126,14 @@ public class CraftProfileBanList implements ProfileBanList { - - @Override - public boolean isBanned(PlayerProfile target) { -+ // Paper start -+ return this.isBanned((com.destroystokyo.paper.profile.SharedPlayerProfile) target); -+ } -+ private boolean isBanned(com.destroystokyo.paper.profile.SharedPlayerProfile target) { -+ // Paper end - Preconditions.checkArgument(target != null, "Target cannot be null"); - -- return this.isBanned(((CraftPlayerProfile) target).buildGameProfile()); -+ return this.isBanned(target.buildGameProfile()); // Paper - } - - @Override -@@ -102,9 +145,14 @@ public class CraftProfileBanList implements ProfileBanList { - - @Override - public void pardon(PlayerProfile target) { -+ // Paper start -+ this.pardon((com.destroystokyo.paper.profile.SharedPlayerProfile) target); -+ } -+ private void pardon(com.destroystokyo.paper.profile.SharedPlayerProfile target) { -+ // Paper end - Preconditions.checkArgument(target != null, "Target cannot be null"); - -- this.pardon(((CraftPlayerProfile) target).buildGameProfile()); -+ this.pardon(target.buildGameProfile()); // Paper - } - - @Override -@@ -114,7 +162,7 @@ public class CraftProfileBanList implements ProfileBanList { - this.pardon(CraftProfileBanList.getProfile(target)); - } - -- public BanEntry getBanEntry(GameProfile profile) { -+ public BanEntry getBanEntry(GameProfile profile) { // Paper - if (profile == null) { - return null; - } -@@ -127,7 +175,7 @@ public class CraftProfileBanList implements ProfileBanList { - return new CraftProfileBanEntry(profile, entry, this.list); - } - -- public BanEntry addBan(GameProfile profile, String reason, Date expires, String source) { -+ public BanEntry addBan(GameProfile profile, String reason, Date expires, String source) { // Paper - if (profile == null) { - return null; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 0d2fd570463d7ad1b6457a8b14303273b97716dd..ccf2c23ecf6f406ae07a2d7614d52e65da8ca586 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1777,23 +1777,23 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - - @Override -- public BanEntry ban(String reason, Date expires, String source) { -+ public BanEntry ban(String reason, Date expires, String source) { // Paper - fix ban list API - return this.ban(reason, expires, source, true); - } - - @Override -- public BanEntry ban(String reason, Instant expires, String source) { -+ public BanEntry ban(String reason, Instant expires, String source) { // Paper - fix ban list API - return this.ban(reason, expires != null ? Date.from(expires) : null, source); - } - - @Override -- public BanEntry ban(String reason, Duration duration, String source) { -+ public BanEntry ban(String reason, Duration duration, String source) { // Paper - fix ban list API - return this.ban(reason, duration != null ? Instant.now().plus(duration) : null, source); - } - - @Override -- public BanEntry ban(String reason, Date expires, String source, boolean kickPlayer) { -- BanEntry banEntry = ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); -+ public BanEntry ban(String reason, Date expires, String source, boolean kickPlayer) { // Paper - fix ban list API -+ BanEntry banEntry = ((ProfileBanList) this.server.getBanList(BanList.Type.PROFILE)).addBan(this.getPlayerProfile(), reason, expires, source); // Paper - fix ban list API - if (kickPlayer) { - this.kickPlayer(reason); - } -@@ -1801,12 +1801,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - - @Override -- public BanEntry ban(String reason, Instant instant, String source, boolean kickPlayer) { -+ public BanEntry ban(String reason, Instant instant, String source, boolean kickPlayer) { // Paper - fix ban list API - return this.ban(reason, instant != null ? Date.from(instant) : null, source, kickPlayer); - } - - @Override -- public BanEntry ban(String reason, Duration duration, String source, boolean kickPlayer) { -+ public BanEntry ban(String reason, Duration duration, String source, boolean kickPlayer) { // Paper - fix ban list API - return this.ban(reason, duration != null ? Instant.now().plus(duration) : null, source, kickPlayer); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java -index d9cc76d7e60001957c0f59fdc32d016f3589aa08..f58dec12326734c61f4bc2298a87fb38f1ac1dc4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java -+++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java -@@ -31,7 +31,7 @@ import org.bukkit.profile.PlayerTextures; - import org.jetbrains.annotations.ApiStatus; - - @SerializableAs("PlayerProfile") --public final class CraftPlayerProfile implements PlayerProfile, com.destroystokyo.paper.profile.SharedPlayerProfile { // Paper -+public final class CraftPlayerProfile implements PlayerProfile, com.destroystokyo.paper.profile.SharedPlayerProfile, com.destroystokyo.paper.profile.PlayerProfile { // Paper - - @Nonnull - public static GameProfile validateSkullProfile(@Nonnull GameProfile gameProfile) { -@@ -162,7 +162,7 @@ public final class CraftPlayerProfile implements PlayerProfile, com.destroystoky - } - - @Override -- public CompletableFuture update() { -+ public CompletableFuture update() { // Paper - have to remove generic to avoid clashing between bukkit.PlayerProfile and paper.PlayerProfile - return CompletableFuture.supplyAsync(this::getUpdatedProfile, Util.PROFILE_EXECUTOR); // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread - } - -@@ -321,4 +321,71 @@ public final class CraftPlayerProfile implements PlayerProfile, com.destroystoky - // Paper - diff on change - return profile; - } -+ -+ // Paper start - This must implement our PlayerProfile so generic casts succeed from cb.CraftPlayerProfile to paper.PlayerProfile -+ // The methods don't actually have to be implemented, because the profile should immediately be cast to SharedPlayerProfile -+ @Override -+ public String setName(final String name) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public UUID getId() { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public UUID setId(final UUID uuid) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public java.util.Set getProperties() { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public boolean hasProperty(final String property) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public void setProperty(final com.destroystokyo.paper.profile.ProfileProperty property) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public void setProperties(final java.util.Collection properties) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public void clearProperties() { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public boolean completeFromCache() { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public boolean completeFromCache(final boolean onlineMode) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public boolean completeFromCache(final boolean lookupUUID, final boolean onlineMode) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public boolean complete(final boolean textures) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } -+ -+ @Override -+ public boolean complete(final boolean textures, final boolean onlineMode) { -+ throw new UnsupportedOperationException("Do not cast to com.destroystokyo.paper.profile.PlayerProfile"); -+ } - } diff --git a/patches/server/0829-Determine-lava-and-water-fluid-explosion-resistance-.patch b/patches/server/0829-Determine-lava-and-water-fluid-explosion-resistance-.patch deleted file mode 100644 index 4f2b8e09cd..0000000000 --- a/patches/server/0829-Determine-lava-and-water-fluid-explosion-resistance-.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: galacticwarrior9 -Date: Thu, 13 Jul 2023 21:32:13 +0100 -Subject: [PATCH] Determine lava and water fluid explosion resistance by their - block explosion resistance - -When selecting which explosion resistance to use for lava and water, vanilla selects the highest value between their block explosion resistance and fluid explosion resistance. - -Problems emerge when we want to reduce the explosion resistance of water or lava, since the fluid explosion resistance is hardcoded to return 100.0F and can't be changed by a plugin. This simply makes the fluid explosion resistance the same as the block explosion resistance, which allows plugin to change the value. Since both are the same in vanilla, this has no side effects on servers that do not need to do this. - -diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java -index a27ceed2cac6c16eb4e5f2959db9e482e67e9de6..884db3e64cb22ed765beec8f11ea309fcf810207 100644 ---- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java -@@ -233,7 +233,7 @@ public abstract class LavaFluid extends FlowingFluid { - - @Override - protected float getExplosionResistance() { -- return 100.0F; -+ return Blocks.LAVA.getExplosionResistance(); // Paper - Get explosion resistance from actual block - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/material/WaterFluid.java b/src/main/java/net/minecraft/world/level/material/WaterFluid.java -index 0a7c05c08bf8c6c331b91e399dc4103a91dc20fe..552925ba47c7475e2e1ec2ded0966f28ed3e50a5 100644 ---- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java -@@ -126,7 +126,7 @@ public abstract class WaterFluid extends FlowingFluid { - - @Override - protected float getExplosionResistance() { -- return 100.0F; -+ return Blocks.WATER.getExplosionResistance(); // Paper - Get explosion resistance from actual block - } - - @Override diff --git a/patches/server/0829-Fix-possible-NPE-on-painting-creation.patch b/patches/server/0829-Fix-possible-NPE-on-painting-creation.patch new file mode 100644 index 0000000000..d5fa31bd07 --- /dev/null +++ b/patches/server/0829-Fix-possible-NPE-on-painting-creation.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 24 Jun 2023 09:42:53 -0700 +Subject: [PATCH] Fix possible NPE on painting creation + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +index 39ea25d2145acaa7c7b458800adc674a3e73e7c1..8715d8e790b6735610e2f880f8c1f88a89967f21 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -361,8 +361,13 @@ public final class CraftEntityTypes { + // Hanging + register(new EntityTypeData<>(EntityType.PAINTING, Painting.class, CraftPainting::new, createHanging(Painting.class, (spawnData, hangingData) -> { + if (spawnData.normalWorld && hangingData.randomize()) { +- return net.minecraft.world.entity.decoration.Painting.create(spawnData.minecraftWorld(), hangingData.position(), hangingData.direction()).orElse(null); +- } else { ++ // Paper start - if randomizeData fails, force it ++ final net.minecraft.world.entity.decoration.Painting entity = net.minecraft.world.entity.decoration.Painting.create(spawnData.minecraftWorld(), hangingData.position(), hangingData.direction()).orElse(null); ++ if (entity != null) { ++ return entity; ++ } ++ } /*else*/ { ++ // Paper end - if randomizeData fails, force it + net.minecraft.world.entity.decoration.Painting entity = new net.minecraft.world.entity.decoration.Painting(net.minecraft.world.entity.EntityType.PAINTING, spawnData.minecraftWorld()); + entity.absMoveTo(spawnData.x(), spawnData.y(), spawnData.z(), spawnData.yaw(), spawnData.pitch()); + entity.setDirection(hangingData.direction()); +@@ -523,6 +528,7 @@ public final class CraftEntityTypes { + AABB bb = (ItemFrame.class.isAssignableFrom(clazz)) + ? net.minecraft.world.entity.decoration.ItemFrame.calculateBoundingBoxStatic(pos, CraftBlock.blockFaceToNotch(dir).getOpposite()) + : net.minecraft.world.entity.decoration.Painting.calculateBoundingBoxStatic(pos, CraftBlock.blockFaceToNotch(dir).getOpposite(), width, height); ++ if (!spawnData.world.noCollision(bb)) continue; // Paper - add collision check + List list = spawnData.world().getEntities(null, bb); + for (Iterator it = list.iterator(); !taken && it.hasNext(); ) { + net.minecraft.world.entity.Entity e = it.next(); diff --git a/patches/server/0830-Fix-possible-NPE-on-painting-creation.patch b/patches/server/0830-Fix-possible-NPE-on-painting-creation.patch deleted file mode 100644 index d5fa31bd07..0000000000 --- a/patches/server/0830-Fix-possible-NPE-on-painting-creation.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 24 Jun 2023 09:42:53 -0700 -Subject: [PATCH] Fix possible NPE on painting creation - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -index 39ea25d2145acaa7c7b458800adc674a3e73e7c1..8715d8e790b6735610e2f880f8c1f88a89967f21 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -361,8 +361,13 @@ public final class CraftEntityTypes { - // Hanging - register(new EntityTypeData<>(EntityType.PAINTING, Painting.class, CraftPainting::new, createHanging(Painting.class, (spawnData, hangingData) -> { - if (spawnData.normalWorld && hangingData.randomize()) { -- return net.minecraft.world.entity.decoration.Painting.create(spawnData.minecraftWorld(), hangingData.position(), hangingData.direction()).orElse(null); -- } else { -+ // Paper start - if randomizeData fails, force it -+ final net.minecraft.world.entity.decoration.Painting entity = net.minecraft.world.entity.decoration.Painting.create(spawnData.minecraftWorld(), hangingData.position(), hangingData.direction()).orElse(null); -+ if (entity != null) { -+ return entity; -+ } -+ } /*else*/ { -+ // Paper end - if randomizeData fails, force it - net.minecraft.world.entity.decoration.Painting entity = new net.minecraft.world.entity.decoration.Painting(net.minecraft.world.entity.EntityType.PAINTING, spawnData.minecraftWorld()); - entity.absMoveTo(spawnData.x(), spawnData.y(), spawnData.z(), spawnData.yaw(), spawnData.pitch()); - entity.setDirection(hangingData.direction()); -@@ -523,6 +528,7 @@ public final class CraftEntityTypes { - AABB bb = (ItemFrame.class.isAssignableFrom(clazz)) - ? net.minecraft.world.entity.decoration.ItemFrame.calculateBoundingBoxStatic(pos, CraftBlock.blockFaceToNotch(dir).getOpposite()) - : net.minecraft.world.entity.decoration.Painting.calculateBoundingBoxStatic(pos, CraftBlock.blockFaceToNotch(dir).getOpposite(), width, height); -+ if (!spawnData.world.noCollision(bb)) continue; // Paper - add collision check - List list = spawnData.world().getEntities(null, bb); - for (Iterator it = list.iterator(); !taken && it.hasNext(); ) { - net.minecraft.world.entity.Entity e = it.next(); diff --git a/patches/server/0830-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch b/patches/server/0830-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch new file mode 100644 index 0000000000..c481798890 --- /dev/null +++ b/patches/server/0830-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Fri, 19 Mar 2021 16:07:21 -0700 +Subject: [PATCH] Only set despawnTimer for Wandering Traders spawned by + WanderingTraderSpawner + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java +index a65fba5621c067c453858efb7fee64cbee1e7916..1e77cce428d9e53142aaa2cf780b7f862d536eca 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -69,7 +69,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + + public WanderingTrader(EntityType type, Level world) { + super(type, world); +- this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader ++ //this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader // Paper - move back to MobSpawnerTrader - Vanilla behavior is that only traders spawned by it have this value set. + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +index 08a3c7140867f339dd99a95094ed0fd8ff344fca..a728dcbf956f108f01c966c7531449a506a14a87 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java ++++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +@@ -120,7 +120,7 @@ public class WanderingTraderSpawner implements CustomSpawner { + return false; + } + +- WanderingTrader entityvillagertrader = (WanderingTrader) EntityType.WANDERING_TRADER.spawn(world, blockposition2, EntitySpawnReason.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit ++ WanderingTrader entityvillagertrader = (WanderingTrader) EntityType.WANDERING_TRADER.spawn(world, trader -> trader.setDespawnDelay(48000), blockposition2, EntitySpawnReason.EVENT, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit // Paper - set despawnTimer before spawn events called + + if (entityvillagertrader != null) { + for (int i = 0; i < 2; ++i) { diff --git a/patches/server/0831-ExperienceOrb-should-call-EntitySpawnEvent.patch b/patches/server/0831-ExperienceOrb-should-call-EntitySpawnEvent.patch new file mode 100644 index 0000000000..40dec00abb --- /dev/null +++ b/patches/server/0831-ExperienceOrb-should-call-EntitySpawnEvent.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Golfing8 +Date: Mon, 8 May 2023 09:18:17 -0400 +Subject: [PATCH] ExperienceOrb should call EntitySpawnEvent + + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 38c8f69dff0abe62fc405a9fbb29c80d45aa675f..449380c97dc332ecd43e308fcf110c9548930600 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -744,7 +744,8 @@ public class CraftEventFactory { + // Spigot start - SPIGOT-7523: Merge after spawn event and only merge if the event was not cancelled (gets checked above) + if (entity instanceof net.minecraft.world.entity.ExperienceOrb xp) { + double radius = world.spigotConfig.expMerge; +- if (radius > 0) { ++ event = CraftEventFactory.callEntitySpawnEvent(entity); // Call spawn event for ExperienceOrb entities ++ if (radius > 0 && !event.isCancelled() && !entity.isRemoved()) { + // Paper start - Maximum exp value when merging; Whole section has been tweaked, see comments for specifics + final long maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue; + final boolean mergeUnconditionally = maxValue <= 0; diff --git a/patches/server/0831-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch b/patches/server/0831-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch deleted file mode 100644 index c481798890..0000000000 --- a/patches/server/0831-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Fri, 19 Mar 2021 16:07:21 -0700 -Subject: [PATCH] Only set despawnTimer for Wandering Traders spawned by - WanderingTraderSpawner - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index a65fba5621c067c453858efb7fee64cbee1e7916..1e77cce428d9e53142aaa2cf780b7f862d536eca 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -69,7 +69,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - - public WanderingTrader(EntityType type, Level world) { - super(type, world); -- this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader -+ //this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader // Paper - move back to MobSpawnerTrader - Vanilla behavior is that only traders spawned by it have this value set. - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -index 08a3c7140867f339dd99a95094ed0fd8ff344fca..a728dcbf956f108f01c966c7531449a506a14a87 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -@@ -120,7 +120,7 @@ public class WanderingTraderSpawner implements CustomSpawner { - return false; - } - -- WanderingTrader entityvillagertrader = (WanderingTrader) EntityType.WANDERING_TRADER.spawn(world, blockposition2, EntitySpawnReason.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit -+ WanderingTrader entityvillagertrader = (WanderingTrader) EntityType.WANDERING_TRADER.spawn(world, trader -> trader.setDespawnDelay(48000), blockposition2, EntitySpawnReason.EVENT, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit // Paper - set despawnTimer before spawn events called - - if (entityvillagertrader != null) { - for (int i = 0; i < 2; ++i) { diff --git a/patches/server/0832-ExperienceOrb-should-call-EntitySpawnEvent.patch b/patches/server/0832-ExperienceOrb-should-call-EntitySpawnEvent.patch deleted file mode 100644 index 40dec00abb..0000000000 --- a/patches/server/0832-ExperienceOrb-should-call-EntitySpawnEvent.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Golfing8 -Date: Mon, 8 May 2023 09:18:17 -0400 -Subject: [PATCH] ExperienceOrb should call EntitySpawnEvent - - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 38c8f69dff0abe62fc405a9fbb29c80d45aa675f..449380c97dc332ecd43e308fcf110c9548930600 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -744,7 +744,8 @@ public class CraftEventFactory { - // Spigot start - SPIGOT-7523: Merge after spawn event and only merge if the event was not cancelled (gets checked above) - if (entity instanceof net.minecraft.world.entity.ExperienceOrb xp) { - double radius = world.spigotConfig.expMerge; -- if (radius > 0) { -+ event = CraftEventFactory.callEntitySpawnEvent(entity); // Call spawn event for ExperienceOrb entities -+ if (radius > 0 && !event.isCancelled() && !entity.isRemoved()) { - // Paper start - Maximum exp value when merging; Whole section has been tweaked, see comments for specifics - final long maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue; - final boolean mergeUnconditionally = maxValue <= 0; diff --git a/patches/server/0832-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch b/patches/server/0832-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch new file mode 100644 index 0000000000..301b345fb9 --- /dev/null +++ b/patches/server/0832-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jacob Litewski +Date: Tue, 13 Jun 2023 19:16:39 -0400 +Subject: [PATCH] Make Amethyst throw both Spread and Grow Events + + +diff --git a/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java b/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java +index 6c402bfd9bed54cbb9b337d3528fdcffbd3d87c0..8920855b07a31715327b8102c7faafc9f916825d 100644 +--- a/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java +@@ -45,7 +45,13 @@ public class BuddingAmethystBlock extends AmethystBlock { + if (block != null) { + BlockState iblockdata2 = (BlockState) ((BlockState) block.defaultBlockState().setValue(AmethystClusterBlock.FACING, enumdirection)).setValue(AmethystClusterBlock.WATERLOGGED, iblockdata1.getFluidState().getType() == Fluids.WATER); + ++ // Paper start - Have Amethyst throw both spread and grow events ++ if (block == Blocks.SMALL_AMETHYST_BUD) { + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, iblockdata2); // CraftBukkit ++ } else { ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, blockposition1, iblockdata2); ++ } ++ // Paper end - Have Amethyst throw both spread and grow events + } + + } diff --git a/patches/server/0833-Add-whitelist-events.patch b/patches/server/0833-Add-whitelist-events.patch new file mode 100644 index 0000000000..96884032fb --- /dev/null +++ b/patches/server/0833-Add-whitelist-events.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SageSphinx63920 +Date: Sun, 14 May 2023 12:57:15 +0200 +Subject: [PATCH] Add whitelist events + + +diff --git a/src/main/java/net/minecraft/server/players/UserWhiteList.java b/src/main/java/net/minecraft/server/players/UserWhiteList.java +index 3226a3b69453fb5e13003e941ccbc2d941e047b0..aaa3d5769e0e184e19d01109a76a65be634f830d 100644 +--- a/src/main/java/net/minecraft/server/players/UserWhiteList.java ++++ b/src/main/java/net/minecraft/server/players/UserWhiteList.java +@@ -28,4 +28,23 @@ public class UserWhiteList extends StoredUserList -Date: Tue, 13 Jun 2023 19:16:39 -0400 -Subject: [PATCH] Make Amethyst throw both Spread and Grow Events - - -diff --git a/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java b/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java -index 6c402bfd9bed54cbb9b337d3528fdcffbd3d87c0..8920855b07a31715327b8102c7faafc9f916825d 100644 ---- a/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BuddingAmethystBlock.java -@@ -45,7 +45,13 @@ public class BuddingAmethystBlock extends AmethystBlock { - if (block != null) { - BlockState iblockdata2 = (BlockState) ((BlockState) block.defaultBlockState().setValue(AmethystClusterBlock.FACING, enumdirection)).setValue(AmethystClusterBlock.WATERLOGGED, iblockdata1.getFluidState().getType() == Fluids.WATER); - -+ // Paper start - Have Amethyst throw both spread and grow events -+ if (block == Blocks.SMALL_AMETHYST_BUD) { - org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, iblockdata2); // CraftBukkit -+ } else { -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, blockposition1, iblockdata2); -+ } -+ // Paper end - Have Amethyst throw both spread and grow events - } - - } diff --git a/patches/server/0834-Add-whitelist-events.patch b/patches/server/0834-Add-whitelist-events.patch deleted file mode 100644 index 96884032fb..0000000000 --- a/patches/server/0834-Add-whitelist-events.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SageSphinx63920 -Date: Sun, 14 May 2023 12:57:15 +0200 -Subject: [PATCH] Add whitelist events - - -diff --git a/src/main/java/net/minecraft/server/players/UserWhiteList.java b/src/main/java/net/minecraft/server/players/UserWhiteList.java -index 3226a3b69453fb5e13003e941ccbc2d941e047b0..aaa3d5769e0e184e19d01109a76a65be634f830d 100644 ---- a/src/main/java/net/minecraft/server/players/UserWhiteList.java -+++ b/src/main/java/net/minecraft/server/players/UserWhiteList.java -@@ -28,4 +28,23 @@ public class UserWhiteList extends StoredUserList +Date: Wed, 26 Jul 2023 20:13:31 +0800 +Subject: [PATCH] Implement PlayerFailMoveEvent + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 919b0ffb69720b3edeb9d25c7f41291a09976505..134d9fbdb757094a4624325c0ad8f32efadd61b6 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1271,8 +1271,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + double d0 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX(this.player.getX())); final double toX = d0; // Paper - OBFHELPER + double d1 = ServerGamePacketListenerImpl.clampVertical(packet.getY(this.player.getY())); final double toY = d1; // Paper - OBFHELPER + double d2 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ(this.player.getZ())); final double toZ = d2; // Paper - OBFHELPER +- float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot())); +- float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot())); ++ float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot())); final float toYaw = f; // Paper - OBFHELPER ++ float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot())); final float toPitch = f1; // Paper - OBFHELPER + + if (this.player.isPassenger()) { + this.player.absMoveTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); +@@ -1339,8 +1339,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + // Paper start - Prevent moving into unloaded chunks + if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (this.player.getX() != toX || this.player.getZ() != toZ) && !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position())))) { +- this.internalTeleport(PositionMoveRotation.of(this.player), Collections.emptySet()); +- return; ++ // Paper start - Add fail move event ++ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_INTO_UNLOADED_CHUNK, ++ toX, toY, toZ, toYaw, toPitch, false); ++ if (!event.isAllowed()) { ++ this.internalTeleport(PositionMoveRotation.of(this.player), Collections.emptySet()); ++ return; ++ } ++ // Paper end - Add fail move event + } + // Paper end - Prevent moving into unloaded chunks + +@@ -1349,9 +1355,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + if (d10 - d9 > Math.max(f2, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2))) { + // CraftBukkit end +- ServerGamePacketListenerImpl.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); +- this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); +- return; ++ // Paper start - Add fail move event ++ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY, ++ toX, toY, toZ, toYaw, toPitch, true); ++ if (!event.isAllowed()) { ++ if (event.getLogWarning()) ++ ServerGamePacketListenerImpl.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); ++ this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); ++ return; ++ } ++ // Paper end - Add fail move event + } + } + } +@@ -1413,14 +1426,31 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + d8 = d2 - this.player.getZ(); + d10 = d6 * d6 + d7 * d7 + d8 * d8; +- boolean flag3 = false; ++ boolean movedWrongly = false; // Paper - Add fail move event; rename + + if (!this.player.isChangingDimension() && d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot +- flag3 = true; ++ // Paper start - Add fail move event ++ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_WRONGLY, ++ toX, toY, toZ, toYaw, toPitch, true); ++ if (!event.isAllowed()) { ++ movedWrongly = true; ++ if (event.getLogWarning()) ++ // Paper end + ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); ++ } // Paper + } + +- if (!this.player.noPhysics && !this.player.isSleeping() && (flag3 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2))) { ++ // Paper start - Add fail move event ++ boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2)); ++ if (teleportBack) { ++ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK, ++ toX, toY, toZ, toYaw, toPitch, false); ++ if (event.isAllowed()) { ++ teleportBack = false; ++ } ++ } ++ if (teleportBack) { ++ // Paper end - Add fail move event + this.internalTeleport(d3, d4, d5, f, f1); // 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. + this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packet.isOnGround()); + } else { +@@ -3534,4 +3564,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand); + } ++ ++ // Paper start - Add fail move event ++ private io.papermc.paper.event.player.PlayerFailMoveEvent fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason failReason, ++ double toX, double toY, double toZ, float toYaw, float toPitch, boolean logWarning) { ++ Player player = this.getCraftPlayer(); ++ Location from = new Location(player.getWorld(), this.lastPosX, this.lastPosY, this.lastPosZ, this.lastYaw, this.lastPitch); ++ Location to = new Location(player.getWorld(), toX, toY, toZ, toYaw, toPitch); ++ io.papermc.paper.event.player.PlayerFailMoveEvent event = new io.papermc.paper.event.player.PlayerFailMoveEvent(player, failReason, ++ false, logWarning, from, to); ++ event.callEvent(); ++ return event; ++ } ++ // Paper end - Add fail move event + } diff --git a/patches/server/0835-Folia-scheduler-and-owned-region-API.patch b/patches/server/0835-Folia-scheduler-and-owned-region-API.patch new file mode 100644 index 0000000000..fe1d592753 --- /dev/null +++ b/patches/server/0835-Folia-scheduler-and-owned-region-API.patch @@ -0,0 +1,1364 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 17 Jun 2023 11:52:52 +0200 +Subject: [PATCH] Folia scheduler and owned region API + +Pulling Folia API to Paper is primarily intended for plugins +that want to target both Paper and Folia without unnecessary +compatibility layers. + +Add both a location based scheduler, an entity based scheduler, +and a global region scheduler. + +Owned region API may be useful for plugins which want to perform +operations over large areas outside of the buffer zone provided +by the regionaliser, as it is not guaranteed that anything +outside of the buffer zone is owned. Then, the plugins may use +the schedulers depending on the result of the ownership check. + +diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java +index d2dee700f2c5cc7d6a272e751a933901fe7a55b6..834b85f24df023642f8abf7213fe578ac8c17a3e 100644 +--- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java ++++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java +@@ -263,6 +263,22 @@ class PaperPluginInstanceManager { + + pluginName + " (Is it up to date?)", ex, plugin); // Paper + } + ++ // Paper start - Folia schedulers ++ try { ++ this.server.getGlobalRegionScheduler().cancelTasks(plugin); ++ } catch (Throwable ex) { ++ this.handlePluginException("Error occurred (in the plugin loader) while cancelling global tasks for " ++ + pluginName + " (Is it up to date?)", ex, plugin); // Paper ++ } ++ ++ try { ++ this.server.getAsyncScheduler().cancelTasks(plugin); ++ } catch (Throwable ex) { ++ this.handlePluginException("Error occurred (in the plugin loader) while cancelling async tasks for " ++ + pluginName + " (Is it up to date?)", ex, plugin); // Paper ++ } ++ // Paper end - Folia schedulers ++ + try { + this.server.getServicesManager().unregisterAll(plugin); + } catch (Throwable ex) { +diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c03608fec96b51e1867f43d8f42e5aefb1520e46 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java +@@ -0,0 +1,181 @@ ++package io.papermc.paper.threadedregions; ++ ++import ca.spottedleaf.concurrentutil.util.Validate; ++import ca.spottedleaf.moonrise.common.util.TickThread; ++import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; ++import net.minecraft.world.entity.Entity; ++import org.bukkit.craftbukkit.entity.CraftEntity; ++ ++import java.util.ArrayDeque; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.function.Consumer; ++ ++/** ++ * An entity can move between worlds with an arbitrary tick delay, be temporarily removed ++ * for players (i.e end credits), be partially removed from world state (i.e inactive but not removed), ++ * teleport between ticking regions, teleport between worlds (which will change the underlying Entity object ++ * for non-players), and even be removed entirely from the server. The uncertainty of an entity's state can make ++ * it difficult to schedule tasks without worrying about undefined behaviors resulting from any of the states listed ++ * previously. ++ * ++ *

++ * This class is designed to eliminate those states by providing an interface to run tasks only when an entity ++ * is contained in a world, on the owning thread for the region, and by providing the current Entity object. ++ * The scheduler also allows a task to provide a callback, the "retired" callback, that will be invoked ++ * if the entity is removed before a task that was scheduled could be executed. The scheduler is also ++ * completely thread-safe, allowing tasks to be scheduled from any thread context. The scheduler also indicates ++ * properly whether a task was scheduled successfully (i.e scheduler not retired), thus the code scheduling any task ++ * knows whether the given callbacks will be invoked eventually or not - which may be critical for off-thread ++ * contexts. ++ *

++ */ ++public final class EntityScheduler { ++ ++ /** ++ * The Entity. Note that it is the CraftEntity, since only that class properly tracks world transfers. ++ */ ++ public final CraftEntity entity; ++ ++ private static final record ScheduledTask(Consumer run, Consumer retired) {} ++ ++ private long tickCount = 0L; ++ private static final long RETIRED_TICK_COUNT = -1L; ++ private final Object stateLock = new Object(); ++ private final Long2ObjectOpenHashMap> oneTimeDelayed = new Long2ObjectOpenHashMap<>(); ++ ++ private final ArrayDeque currentlyExecuting = new ArrayDeque<>(); ++ ++ public EntityScheduler(final CraftEntity entity) { ++ this.entity = Validate.notNull(entity); ++ } ++ ++ /** ++ * Retires the scheduler, preventing new tasks from being scheduled and invoking the retired callback ++ * on all currently scheduled tasks. ++ * ++ *

++ * Note: This should only be invoked after synchronously removing the entity from the world. ++ *

++ * ++ * @throws IllegalStateException If the scheduler is already retired. ++ */ ++ public void retire() { ++ synchronized (this.stateLock) { ++ if (this.tickCount == RETIRED_TICK_COUNT) { ++ throw new IllegalStateException("Already retired"); ++ } ++ this.tickCount = RETIRED_TICK_COUNT; ++ } ++ ++ final Entity thisEntity = this.entity.getHandleRaw(); ++ ++ // correctly handle and order retiring while running executeTick ++ for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) { ++ final ScheduledTask task = this.currentlyExecuting.pollFirst(); ++ final Consumer retireTask = (Consumer)task.retired; ++ if (retireTask == null) { ++ continue; ++ } ++ ++ retireTask.accept(thisEntity); ++ } ++ ++ for (final List tasks : this.oneTimeDelayed.values()) { ++ for (int i = 0, len = tasks.size(); i < len; ++i) { ++ final ScheduledTask task = tasks.get(i); ++ final Consumer retireTask = (Consumer)task.retired; ++ if (retireTask == null) { ++ continue; ++ } ++ ++ retireTask.accept(thisEntity); ++ } ++ } ++ } ++ ++ /** ++ * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity ++ * removed), then returns {@code false}. Otherwise, either the run callback will be invoked after the specified delay, ++ * or the retired callback will be invoked if the scheduler is retired. ++ * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove ++ * other entities, load chunks, load worlds, modify ticket levels, etc. ++ * ++ *

++ * It is guaranteed that the run and retired callback are invoked on the region which owns the entity. ++ *

++ *

++ * The run and retired callback take an Entity parameter representing the current object entity that the scheduler ++ * is tied to. Since the scheduler is transferred when an entity changes dimensions, it is possible the entity parameter ++ * is not the same when the task was first scheduled. Thus, only the parameter provided should be used. ++ *

++ * @param run The callback to run after the specified delay, may not be null. ++ * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. ++ * @param delay The delay in ticks before the run callback is invoked. Any value less-than 1 is treated as 1. ++ * @return {@code true} if the task was scheduled, which means that either the run function or the retired function ++ * will be invoked (but never both), or {@code false} indicating neither the run nor retired function will be invoked ++ * since the scheduler has been retired. ++ */ ++ public boolean schedule(final Consumer run, final Consumer retired, final long delay) { ++ Validate.notNull(run, "Run task may not be null"); ++ ++ final ScheduledTask task = new ScheduledTask(run, retired); ++ synchronized (this.stateLock) { ++ if (this.tickCount == RETIRED_TICK_COUNT) { ++ return false; ++ } ++ this.oneTimeDelayed.computeIfAbsent(this.tickCount + Math.max(1L, delay), (final long keyInMap) -> { ++ return new ArrayList<>(); ++ }).add(task); ++ } ++ ++ return true; ++ } ++ ++ /** ++ * Executes a tick for the scheduler. ++ * ++ * @throws IllegalStateException If the scheduler is retired. ++ */ ++ public void executeTick() { ++ final Entity thisEntity = this.entity.getHandleRaw(); ++ ++ TickThread.ensureTickThread(thisEntity, "May not tick entity scheduler asynchronously"); ++ final List toRun; ++ synchronized (this.stateLock) { ++ if (this.tickCount == RETIRED_TICK_COUNT) { ++ throw new IllegalStateException("Ticking retired scheduler"); ++ } ++ ++this.tickCount; ++ if (this.oneTimeDelayed.isEmpty()) { ++ toRun = null; ++ } else { ++ toRun = this.oneTimeDelayed.remove(this.tickCount); ++ } ++ } ++ ++ if (toRun != null) { ++ for (int i = 0, len = toRun.size(); i < len; ++i) { ++ this.currentlyExecuting.addLast(toRun.get(i)); ++ } ++ } ++ ++ // Note: It is allowed for the tasks executed to retire the entity in a given task. ++ for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) { ++ if (!TickThread.isTickThreadFor(thisEntity)) { ++ // tp has been queued sync by one of the tasks ++ // in this case, we need to delay the tasks for next tick ++ break; ++ } ++ final ScheduledTask task = this.currentlyExecuting.pollFirst(); ++ ++ if (this.tickCount != RETIRED_TICK_COUNT) { ++ ((Consumer)task.run).accept(thisEntity); ++ } else { ++ // retired synchronously ++ // note: here task is null ++ break; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FallbackRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FallbackRegionScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..94056d61a304ee012ae1828a33412516095f996f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FallbackRegionScheduler.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import org.bukkit.World; ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.function.Consumer; ++ ++public final class FallbackRegionScheduler implements RegionScheduler { ++ ++ @Override ++ public void execute(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Runnable run) { ++ plugin.getServer().getGlobalRegionScheduler().execute(plugin, run); ++ } ++ ++ @Override ++ public @NotNull ScheduledTask run(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Consumer task) { ++ return plugin.getServer().getGlobalRegionScheduler().run(plugin, task); ++ } ++ ++ @Override ++ public @NotNull ScheduledTask runDelayed(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Consumer task, final long delayTicks) { ++ return plugin.getServer().getGlobalRegionScheduler().runDelayed(plugin, task, delayTicks); ++ } ++ ++ @Override ++ public @NotNull ScheduledTask runAtFixedRate(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Consumer task, final long initialDelayTicks, final long periodTicks) { ++ return plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, task, initialDelayTicks, periodTicks); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaAsyncScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaAsyncScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..374abffb9f1ce1a308822aed13038e77fe9ca08b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaAsyncScheduler.java +@@ -0,0 +1,328 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import ca.spottedleaf.concurrentutil.util.Validate; ++import com.mojang.logging.LogUtils; ++import org.bukkit.plugin.IllegalPluginAccessException; ++import org.bukkit.plugin.Plugin; ++import org.slf4j.Logger; ++ ++import java.util.Set; ++import java.util.concurrent.ConcurrentHashMap; ++import java.util.concurrent.Executor; ++import java.util.concurrent.Executors; ++import java.util.concurrent.ScheduledExecutorService; ++import java.util.concurrent.ScheduledFuture; ++import java.util.concurrent.SynchronousQueue; ++import java.util.concurrent.ThreadFactory; ++import java.util.concurrent.ThreadPoolExecutor; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.atomic.AtomicInteger; ++import java.util.function.Consumer; ++import java.util.logging.Level; ++ ++public final class FoliaAsyncScheduler implements AsyncScheduler { ++ ++ private static final Logger LOGGER = LogUtils.getClassLogger(); ++ ++ private final Executor executors = new ThreadPoolExecutor(Math.max(4, Runtime.getRuntime().availableProcessors() / 2), Integer.MAX_VALUE, ++ 30L, TimeUnit.SECONDS, new SynchronousQueue<>(), ++ new ThreadFactory() { ++ private final AtomicInteger idGenerator = new AtomicInteger(); ++ ++ @Override ++ public Thread newThread(final Runnable run) { ++ final Thread ret = new Thread(run); ++ ++ ret.setName("Folia Async Scheduler Thread #" + this.idGenerator.getAndIncrement()); ++ ret.setPriority(Thread.NORM_PRIORITY - 1); ++ ret.setUncaughtExceptionHandler((final Thread thread, final Throwable thr) -> { ++ LOGGER.error("Uncaught exception in thread: " + thread.getName(), thr); ++ }); ++ ++ return ret; ++ } ++ } ++ ); ++ ++ private final ScheduledExecutorService timerThread = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { ++ @Override ++ public Thread newThread(final Runnable run) { ++ final Thread ret = new Thread(run); ++ ++ ret.setName("Folia Async Scheduler Thread Timer"); ++ ret.setPriority(Thread.NORM_PRIORITY + 1); ++ ret.setUncaughtExceptionHandler((final Thread thread, final Throwable thr) -> { ++ LOGGER.error("Uncaught exception in thread: " + thread.getName(), thr); ++ }); ++ ++ return ret; ++ } ++ }); ++ ++ private final Set tasks = ConcurrentHashMap.newKeySet(); ++ ++ @Override ++ public ScheduledTask runNow(final Plugin plugin, final Consumer task) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(task, "Task may not be null"); ++ ++ if (!plugin.isEnabled()) { ++ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); ++ } ++ ++ final AsyncScheduledTask ret = new AsyncScheduledTask(plugin, -1L, task, null, -1L); ++ ++ this.tasks.add(ret); ++ this.executors.execute(ret); ++ ++ if (!plugin.isEnabled()) { ++ // handle race condition where plugin is disabled asynchronously ++ ret.cancel(); ++ } ++ ++ return ret; ++ } ++ ++ @Override ++ public ScheduledTask runDelayed(final Plugin plugin, final Consumer task, final long delay, ++ final TimeUnit unit) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(task, "Task may not be null"); ++ Validate.notNull(unit, "Time unit may not be null"); ++ if (delay < 0L) { ++ throw new IllegalArgumentException("Delay may not be < 0"); ++ } ++ ++ if (!plugin.isEnabled()) { ++ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); ++ } ++ ++ return this.scheduleTimerTask(plugin, task, delay, -1L, unit); ++ } ++ ++ @Override ++ public ScheduledTask runAtFixedRate(final Plugin plugin, final Consumer task, final long initialDelay, ++ final long period, final TimeUnit unit) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(task, "Task may not be null"); ++ Validate.notNull(unit, "Time unit may not be null"); ++ if (initialDelay < 0L) { ++ throw new IllegalArgumentException("Initial delay may not be < 0"); ++ } ++ if (period <= 0L) { ++ throw new IllegalArgumentException("Period may not be <= 0"); ++ } ++ ++ if (!plugin.isEnabled()) { ++ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); ++ } ++ ++ return this.scheduleTimerTask(plugin, task, initialDelay, period, unit); ++ } ++ ++ private AsyncScheduledTask scheduleTimerTask(final Plugin plugin, final Consumer task, final long initialDelay, ++ final long period, final TimeUnit unit) { ++ final AsyncScheduledTask ret = new AsyncScheduledTask( ++ plugin, period <= 0 ? period : unit.toNanos(period), task, null, ++ System.nanoTime() + unit.toNanos(initialDelay) ++ ); ++ ++ synchronized (ret) { ++ // even though ret is not published, we need to synchronise while scheduling to avoid a race condition ++ // for when a scheduled task immediately executes before we update the delay field and state field ++ ret.setDelay(this.timerThread.schedule(ret, initialDelay, unit)); ++ this.tasks.add(ret); ++ } ++ ++ if (!plugin.isEnabled()) { ++ // handle race condition where plugin is disabled asynchronously ++ ret.cancel(); ++ } ++ ++ return ret; ++ } ++ ++ @Override ++ public void cancelTasks(final Plugin plugin) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ ++ for (final AsyncScheduledTask task : this.tasks) { ++ if (task.plugin == plugin) { ++ task.cancel(); ++ } ++ } ++ } ++ ++ private final class AsyncScheduledTask implements ScheduledTask, Runnable { ++ ++ private static final int STATE_ON_TIMER = 0; ++ private static final int STATE_SCHEDULED_EXECUTOR = 1; ++ private static final int STATE_EXECUTING = 2; ++ private static final int STATE_EXECUTING_CANCELLED = 3; ++ private static final int STATE_FINISHED = 4; ++ private static final int STATE_CANCELLED = 5; ++ ++ private final Plugin plugin; ++ private final long repeatDelay; // in ns ++ private Consumer run; ++ private ScheduledFuture delay; ++ private int state; ++ private long scheduleTarget; ++ ++ public AsyncScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer run, ++ final ScheduledFuture delay, final long firstTarget) { ++ this.plugin = plugin; ++ this.repeatDelay = repeatDelay; ++ this.run = run; ++ this.delay = delay; ++ this.state = delay == null ? STATE_SCHEDULED_EXECUTOR : STATE_ON_TIMER; ++ this.scheduleTarget = firstTarget; ++ } ++ ++ private void setDelay(final ScheduledFuture delay) { ++ this.delay = delay; ++ this.state = STATE_SCHEDULED_EXECUTOR; ++ } ++ ++ @Override ++ public void run() { ++ final boolean repeating = this.isRepeatingTask(); ++ // try to advance state ++ final boolean timer; ++ synchronized (this) { ++ if (this.state == STATE_ON_TIMER) { ++ timer = true; ++ this.delay = null; ++ this.state = STATE_SCHEDULED_EXECUTOR; ++ } else if (this.state != STATE_SCHEDULED_EXECUTOR) { ++ // cancelled ++ if (this.state != STATE_CANCELLED) { ++ throw new IllegalStateException("Wrong state: " + this.state); ++ } ++ return; ++ } else { ++ timer = false; ++ this.state = STATE_EXECUTING; ++ } ++ } ++ ++ if (timer) { ++ // the scheduled executor is single thread, and unfortunately not expandable with threads ++ // so we just schedule onto the executor ++ FoliaAsyncScheduler.this.executors.execute(this); ++ return; ++ } ++ ++ try { ++ this.run.accept(this); ++ } catch (final Throwable throwable) { ++ this.plugin.getLogger().log(Level.WARNING, "Async task for " + this.plugin.getDescription().getFullName() + " generated an exception", throwable); ++ } finally { ++ boolean removeFromTasks = false; ++ synchronized (this) { ++ if (!repeating) { ++ // only want to execute once, so we're done ++ removeFromTasks = true; ++ this.state = STATE_FINISHED; ++ } else if (this.state != STATE_EXECUTING_CANCELLED) { ++ this.state = STATE_ON_TIMER; ++ // account for any delays, whether it be by task exec. or scheduler issues so that we keep ++ // the fixed schedule ++ final long currTime = System.nanoTime(); ++ final long delay = Math.max(0L, this.scheduleTarget + this.repeatDelay - currTime); ++ this.scheduleTarget = currTime + delay; ++ this.delay = FoliaAsyncScheduler.this.timerThread.schedule(this, delay, TimeUnit.NANOSECONDS); ++ } else { ++ // cancelled repeating task ++ removeFromTasks = true; ++ } ++ } ++ ++ if (removeFromTasks) { ++ this.run = null; ++ FoliaAsyncScheduler.this.tasks.remove(this); ++ } ++ } ++ } ++ ++ @Override ++ public Plugin getOwningPlugin() { ++ return this.plugin; ++ } ++ ++ @Override ++ public boolean isRepeatingTask() { ++ return this.repeatDelay > 0L; ++ } ++ ++ @Override ++ public CancelledState cancel() { ++ ScheduledFuture delay = null; ++ CancelledState ret; ++ synchronized (this) { ++ switch (this.state) { ++ case STATE_ON_TIMER: { ++ delay = this.delay; ++ this.delay = null; ++ this.state = STATE_CANCELLED; ++ ret = CancelledState.CANCELLED_BY_CALLER; ++ break; ++ } ++ case STATE_SCHEDULED_EXECUTOR: { ++ this.state = STATE_CANCELLED; ++ ret = CancelledState.CANCELLED_BY_CALLER; ++ break; ++ } ++ case STATE_EXECUTING: { ++ if (!this.isRepeatingTask()) { ++ return CancelledState.RUNNING; ++ } ++ this.state = STATE_EXECUTING_CANCELLED; ++ return CancelledState.NEXT_RUNS_CANCELLED; ++ } ++ case STATE_EXECUTING_CANCELLED: { ++ return CancelledState.NEXT_RUNS_CANCELLED_ALREADY; ++ } ++ case STATE_FINISHED: { ++ return CancelledState.ALREADY_EXECUTED; ++ } ++ case STATE_CANCELLED: { ++ return CancelledState.CANCELLED_ALREADY; ++ } ++ default: { ++ throw new IllegalStateException("Unknown state: " + this.state); ++ } ++ } ++ } ++ ++ if (delay != null) { ++ delay.cancel(false); ++ } ++ this.run = null; ++ FoliaAsyncScheduler.this.tasks.remove(this); ++ return ret; ++ } ++ ++ @Override ++ public ExecutionState getExecutionState() { ++ synchronized (this) { ++ switch (this.state) { ++ case STATE_ON_TIMER: ++ case STATE_SCHEDULED_EXECUTOR: ++ return ExecutionState.IDLE; ++ case STATE_EXECUTING: ++ return ExecutionState.RUNNING; ++ case STATE_EXECUTING_CANCELLED: ++ return ExecutionState.CANCELLED_RUNNING; ++ case STATE_FINISHED: ++ return ExecutionState.FINISHED; ++ case STATE_CANCELLED: ++ return ExecutionState.CANCELLED; ++ default: { ++ throw new IllegalStateException("Unknown state: " + this.state); ++ } ++ } ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaEntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaEntityScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..011754962896e32f51ed4606dcbea18a430a2bc1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaEntityScheduler.java +@@ -0,0 +1,268 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import ca.spottedleaf.concurrentutil.util.Validate; ++import net.minecraft.world.entity.Entity; ++import org.bukkit.craftbukkit.entity.CraftEntity; ++import org.bukkit.plugin.IllegalPluginAccessException; ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.Nullable; ++ ++import java.lang.invoke.VarHandle; ++import java.util.function.Consumer; ++import java.util.logging.Level; ++ ++public final class FoliaEntityScheduler implements EntityScheduler { ++ ++ private final CraftEntity entity; ++ ++ public FoliaEntityScheduler(final CraftEntity entity) { ++ this.entity = entity; ++ } ++ ++ private static Consumer wrap(final Plugin plugin, final Runnable runnable) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(runnable, "Runnable may not be null"); ++ ++ return (final Entity nmsEntity) -> { ++ if (!plugin.isEnabled()) { ++ // don't execute if the plugin is disabled ++ return; ++ } ++ try { ++ runnable.run(); ++ } catch (final Throwable throwable) { ++ plugin.getLogger().log(Level.WARNING, "Entity task for " + plugin.getDescription().getFullName() + " generated an exception", throwable); ++ } ++ }; ++ } ++ ++ @Override ++ public boolean execute(final Plugin plugin, final Runnable run, final Runnable retired, ++ final long delay) { ++ final Consumer runNMS = wrap(plugin, run); ++ final Consumer runRetired = retired == null ? null : wrap(plugin, retired); ++ ++ return this.entity.taskScheduler.schedule(runNMS, runRetired, delay); ++ } ++ ++ @Override ++ public @Nullable ScheduledTask run(final Plugin plugin, final Consumer task, final Runnable retired) { ++ return this.runDelayed(plugin, task, retired, 1); ++ } ++ ++ @Override ++ public @Nullable ScheduledTask runDelayed(final Plugin plugin, final Consumer task, final Runnable retired, ++ final long delayTicks) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(task, "Task may not be null"); ++ if (delayTicks <= 0) { ++ throw new IllegalArgumentException("Delay ticks may not be <= 0"); ++ } ++ ++ if (!plugin.isEnabled()) { ++ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); ++ } ++ ++ final EntityScheduledTask ret = new EntityScheduledTask(plugin, -1, task, retired); ++ ++ if (!this.scheduleInternal(ret, delayTicks)) { ++ return null; ++ } ++ ++ if (!plugin.isEnabled()) { ++ // handle race condition where plugin is disabled asynchronously ++ ret.cancel(); ++ } ++ ++ return ret; ++ } ++ ++ @Override ++ public @Nullable ScheduledTask runAtFixedRate(final Plugin plugin, final Consumer task, ++ final Runnable retired, final long initialDelayTicks, final long periodTicks) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(task, "Task may not be null"); ++ if (initialDelayTicks <= 0) { ++ throw new IllegalArgumentException("Initial delay ticks may not be <= 0"); ++ } ++ if (periodTicks <= 0) { ++ throw new IllegalArgumentException("Period ticks may not be <= 0"); ++ } ++ ++ if (!plugin.isEnabled()) { ++ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); ++ } ++ ++ final EntityScheduledTask ret = new EntityScheduledTask(plugin, periodTicks, task, retired); ++ ++ if (!this.scheduleInternal(ret, initialDelayTicks)) { ++ return null; ++ } ++ ++ if (!plugin.isEnabled()) { ++ // handle race condition where plugin is disabled asynchronously ++ ret.cancel(); ++ } ++ ++ return ret; ++ } ++ ++ private boolean scheduleInternal(final EntityScheduledTask ret, final long delay) { ++ return this.entity.taskScheduler.schedule(ret, ret, delay); ++ } ++ ++ private final class EntityScheduledTask implements ScheduledTask, Consumer { ++ ++ private static final int STATE_IDLE = 0; ++ private static final int STATE_EXECUTING = 1; ++ private static final int STATE_EXECUTING_CANCELLED = 2; ++ private static final int STATE_FINISHED = 3; ++ private static final int STATE_CANCELLED = 4; ++ ++ private final Plugin plugin; ++ private final long repeatDelay; // in ticks ++ private Consumer run; ++ private Runnable retired; ++ private volatile int state; ++ ++ private static final VarHandle STATE_HANDLE = ConcurrentUtil.getVarHandle(EntityScheduledTask.class, "state", int.class); ++ ++ private EntityScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer run, final Runnable retired) { ++ this.plugin = plugin; ++ this.repeatDelay = repeatDelay; ++ this.run = run; ++ this.retired = retired; ++ } ++ ++ private final int getStateVolatile() { ++ return (int)STATE_HANDLE.get(this); ++ } ++ ++ private final int compareAndExchangeStateVolatile(final int expect, final int update) { ++ return (int)STATE_HANDLE.compareAndExchange(this, expect, update); ++ } ++ ++ private final void setStateVolatile(final int value) { ++ STATE_HANDLE.setVolatile(this, value); ++ } ++ ++ @Override ++ public void accept(final Entity entity) { ++ if (!this.plugin.isEnabled()) { ++ // don't execute if the plugin is disabled ++ this.setStateVolatile(STATE_CANCELLED); ++ return; ++ } ++ ++ final boolean repeating = this.isRepeatingTask(); ++ if (STATE_IDLE != this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_EXECUTING)) { ++ // cancelled ++ return; ++ } ++ ++ final boolean retired = entity.isRemoved(); ++ ++ try { ++ if (!retired) { ++ this.run.accept(this); ++ } else { ++ if (this.retired != null) { ++ this.retired.run(); ++ } ++ } ++ } catch (final Throwable throwable) { ++ this.plugin.getLogger().log(Level.WARNING, "Entity task for " + this.plugin.getDescription().getFullName() + " generated an exception", throwable); ++ } finally { ++ boolean reschedule = false; ++ if (!repeating && !retired) { ++ this.setStateVolatile(STATE_FINISHED); ++ } else if (retired || !this.plugin.isEnabled()) { ++ this.setStateVolatile(STATE_CANCELLED); ++ } else if (STATE_EXECUTING == this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_IDLE)) { ++ reschedule = true; ++ } // else: cancelled repeating task ++ ++ if (!reschedule) { ++ this.run = null; ++ this.retired = null; ++ } else { ++ if (!FoliaEntityScheduler.this.scheduleInternal(this, this.repeatDelay)) { ++ // the task itself must have removed the entity, so in this case we need to mark as cancelled ++ this.setStateVolatile(STATE_CANCELLED); ++ } ++ } ++ } ++ } ++ ++ @Override ++ public Plugin getOwningPlugin() { ++ return this.plugin; ++ } ++ ++ @Override ++ public boolean isRepeatingTask() { ++ return this.repeatDelay > 0; ++ } ++ ++ @Override ++ public CancelledState cancel() { ++ for (int curr = this.getStateVolatile();;) { ++ switch (curr) { ++ case STATE_IDLE: { ++ if (STATE_IDLE == (curr = this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_CANCELLED))) { ++ this.state = STATE_CANCELLED; ++ this.run = null; ++ this.retired = null; ++ return CancelledState.CANCELLED_BY_CALLER; ++ } ++ // try again ++ continue; ++ } ++ case STATE_EXECUTING: { ++ if (!this.isRepeatingTask()) { ++ return CancelledState.RUNNING; ++ } ++ if (STATE_EXECUTING == (curr = this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_EXECUTING_CANCELLED))) { ++ return CancelledState.NEXT_RUNS_CANCELLED; ++ } ++ // try again ++ continue; ++ } ++ case STATE_EXECUTING_CANCELLED: { ++ return CancelledState.NEXT_RUNS_CANCELLED_ALREADY; ++ } ++ case STATE_FINISHED: { ++ return CancelledState.ALREADY_EXECUTED; ++ } ++ case STATE_CANCELLED: { ++ return CancelledState.CANCELLED_ALREADY; ++ } ++ default: { ++ throw new IllegalStateException("Unknown state: " + curr); ++ } ++ } ++ } ++ } ++ ++ @Override ++ public ExecutionState getExecutionState() { ++ final int state = this.getStateVolatile(); ++ switch (state) { ++ case STATE_IDLE: ++ return ExecutionState.IDLE; ++ case STATE_EXECUTING: ++ return ExecutionState.RUNNING; ++ case STATE_EXECUTING_CANCELLED: ++ return ExecutionState.CANCELLED_RUNNING; ++ case STATE_FINISHED: ++ return ExecutionState.FINISHED; ++ case STATE_CANCELLED: ++ return ExecutionState.CANCELLED; ++ default: { ++ throw new IllegalStateException("Unknown state: " + state); ++ } ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d306f911757a4d556c82c0070d4837db87afc497 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java +@@ -0,0 +1,267 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import ca.spottedleaf.concurrentutil.util.Validate; ++import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; ++import org.bukkit.plugin.IllegalPluginAccessException; ++import org.bukkit.plugin.Plugin; ++ ++import java.lang.invoke.VarHandle; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.function.Consumer; ++import java.util.logging.Level; ++ ++public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler { ++ ++ private long tickCount = 0L; ++ private final Object stateLock = new Object(); ++ private final Long2ObjectOpenHashMap> tasksByDeadline = new Long2ObjectOpenHashMap<>(); ++ ++ public void tick() { ++ final List run; ++ synchronized (this.stateLock) { ++ ++this.tickCount; ++ if (this.tasksByDeadline.isEmpty()) { ++ run = null; ++ } else { ++ run = this.tasksByDeadline.remove(this.tickCount); ++ } ++ } ++ ++ if (run == null) { ++ return; ++ } ++ ++ for (int i = 0, len = run.size(); i < len; ++i) { ++ run.get(i).run(); ++ } ++ } ++ ++ @Override ++ public void execute(final Plugin plugin, final Runnable run) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(run, "Runnable may not be null"); ++ ++ this.run(plugin, (final ScheduledTask task) -> { ++ run.run(); ++ }); ++ } ++ ++ @Override ++ public ScheduledTask run(final Plugin plugin, final Consumer task) { ++ return this.runDelayed(plugin, task, 1); ++ } ++ ++ @Override ++ public ScheduledTask runDelayed(final Plugin plugin, final Consumer task, final long delayTicks) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(task, "Task may not be null"); ++ if (delayTicks <= 0) { ++ throw new IllegalArgumentException("Delay ticks may not be <= 0"); ++ } ++ ++ if (!plugin.isEnabled()) { ++ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); ++ } ++ ++ final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, -1, task); ++ ++ this.scheduleInternal(ret, delayTicks); ++ ++ if (!plugin.isEnabled()) { ++ // handle race condition where plugin is disabled asynchronously ++ ret.cancel(); ++ } ++ ++ return ret; ++ } ++ ++ @Override ++ public ScheduledTask runAtFixedRate(final Plugin plugin, final Consumer task, final long initialDelayTicks, final long periodTicks) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ Validate.notNull(task, "Task may not be null"); ++ if (initialDelayTicks <= 0) { ++ throw new IllegalArgumentException("Initial delay ticks may not be <= 0"); ++ } ++ if (periodTicks <= 0) { ++ throw new IllegalArgumentException("Period ticks may not be <= 0"); ++ } ++ ++ if (!plugin.isEnabled()) { ++ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); ++ } ++ ++ final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, periodTicks, task); ++ ++ this.scheduleInternal(ret, initialDelayTicks); ++ ++ if (!plugin.isEnabled()) { ++ // handle race condition where plugin is disabled asynchronously ++ ret.cancel(); ++ } ++ ++ return ret; ++ } ++ ++ @Override ++ public void cancelTasks(final Plugin plugin) { ++ Validate.notNull(plugin, "Plugin may not be null"); ++ ++ final List toCancel = new ArrayList<>(); ++ synchronized (this.stateLock) { ++ for (final List tasks : this.tasksByDeadline.values()) { ++ for (int i = 0, len = tasks.size(); i < len; ++i) { ++ final GlobalScheduledTask task = tasks.get(i); ++ if (task.plugin == plugin) { ++ toCancel.add(task); ++ } ++ } ++ } ++ } ++ ++ for (int i = 0, len = toCancel.size(); i < len; ++i) { ++ toCancel.get(i).cancel(); ++ } ++ } ++ ++ private void scheduleInternal(final GlobalScheduledTask task, final long delay) { ++ // note: delay > 0 ++ synchronized (this.stateLock) { ++ this.tasksByDeadline.computeIfAbsent(this.tickCount + delay, (final long keyInMap) -> { ++ return new ArrayList<>(); ++ }).add(task); ++ } ++ } ++ ++ private final class GlobalScheduledTask implements ScheduledTask, Runnable { ++ ++ private static final int STATE_IDLE = 0; ++ private static final int STATE_EXECUTING = 1; ++ private static final int STATE_EXECUTING_CANCELLED = 2; ++ private static final int STATE_FINISHED = 3; ++ private static final int STATE_CANCELLED = 4; ++ ++ private final Plugin plugin; ++ private final long repeatDelay; // in ticks ++ private Consumer run; ++ private volatile int state; ++ ++ private static final VarHandle STATE_HANDLE = ConcurrentUtil.getVarHandle(GlobalScheduledTask.class, "state", int.class); ++ ++ private GlobalScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer run) { ++ this.plugin = plugin; ++ this.repeatDelay = repeatDelay; ++ this.run = run; ++ } ++ ++ private final int getStateVolatile() { ++ return (int)STATE_HANDLE.get(this); ++ } ++ ++ private final int compareAndExchangeStateVolatile(final int expect, final int update) { ++ return (int)STATE_HANDLE.compareAndExchange(this, expect, update); ++ } ++ ++ private final void setStateVolatile(final int value) { ++ STATE_HANDLE.setVolatile(this, value); ++ } ++ ++ @Override ++ public void run() { ++ final boolean repeating = this.isRepeatingTask(); ++ if (STATE_IDLE != this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_EXECUTING)) { ++ // cancelled ++ return; ++ } ++ ++ try { ++ this.run.accept(this); ++ } catch (final Throwable throwable) { ++ this.plugin.getLogger().log(Level.WARNING, "Global task for " + this.plugin.getDescription().getFullName() + " generated an exception", throwable); ++ } finally { ++ boolean reschedule = false; ++ if (!repeating) { ++ this.setStateVolatile(STATE_FINISHED); ++ } else if (STATE_EXECUTING == this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_IDLE)) { ++ reschedule = true; ++ } // else: cancelled repeating task ++ ++ if (!reschedule) { ++ this.run = null; ++ } else { ++ FoliaGlobalRegionScheduler.this.scheduleInternal(this, this.repeatDelay); ++ } ++ } ++ } ++ ++ @Override ++ public Plugin getOwningPlugin() { ++ return this.plugin; ++ } ++ ++ @Override ++ public boolean isRepeatingTask() { ++ return this.repeatDelay > 0; ++ } ++ ++ @Override ++ public CancelledState cancel() { ++ for (int curr = this.getStateVolatile();;) { ++ switch (curr) { ++ case STATE_IDLE: { ++ if (STATE_IDLE == (curr = this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_CANCELLED))) { ++ this.state = STATE_CANCELLED; ++ this.run = null; ++ return CancelledState.CANCELLED_BY_CALLER; ++ } ++ // try again ++ continue; ++ } ++ case STATE_EXECUTING: { ++ if (!this.isRepeatingTask()) { ++ return CancelledState.RUNNING; ++ } ++ if (STATE_EXECUTING == (curr = this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_EXECUTING_CANCELLED))) { ++ return CancelledState.NEXT_RUNS_CANCELLED; ++ } ++ // try again ++ continue; ++ } ++ case STATE_EXECUTING_CANCELLED: { ++ return CancelledState.NEXT_RUNS_CANCELLED_ALREADY; ++ } ++ case STATE_FINISHED: { ++ return CancelledState.ALREADY_EXECUTED; ++ } ++ case STATE_CANCELLED: { ++ return CancelledState.CANCELLED_ALREADY; ++ } ++ default: { ++ throw new IllegalStateException("Unknown state: " + curr); ++ } ++ } ++ } ++ } ++ ++ @Override ++ public ExecutionState getExecutionState() { ++ final int state = this.getStateVolatile(); ++ switch (state) { ++ case STATE_IDLE: ++ return ExecutionState.IDLE; ++ case STATE_EXECUTING: ++ return ExecutionState.RUNNING; ++ case STATE_EXECUTING_CANCELLED: ++ return ExecutionState.CANCELLED_RUNNING; ++ case STATE_FINISHED: ++ return ExecutionState.FINISHED; ++ case STATE_CANCELLED: ++ return ExecutionState.CANCELLED; ++ default: { ++ throw new IllegalStateException("Unknown state: " + state); ++ } ++ } ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 8f7a808b0c89953a7f2932e68e2c85f9330469f2..be188079f12b3f7b394ae91db62cc17b1d0f4e79 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1625,6 +1625,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { ++ for (final Entity entity : level.getEntities().getAll()) { ++ if (entity.isRemoved()) { ++ continue; ++ } ++ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw(); ++ if (bukkit != null) { ++ bukkit.taskScheduler.executeTick(); ++ } ++ } ++ }); ++ // Paper end - Folia scheduler API + io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper + gameprofilerfiller.push("commandFunctions"); + this.getFunctions().tick(); +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index af0ea5b5bbc35cced959beb3ecb576fff46c6a51..74cbc6092d49f573f7fab1895c42a0360bb80bdf 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -597,6 +597,7 @@ public abstract class PlayerList { + } + + worldserver.removePlayerImmediately(entityplayer, Entity.RemovalReason.UNLOADED_WITH_PLAYER); ++ entityplayer.retireScheduler(); // Paper - Folia schedulers + entityplayer.getAdvancements().stopListening(); + this.players.remove(entityplayer); + this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 3444b1a2da80b85e2b1928d69ff0dd980c5fb34f..463dd4f91212318b51174c5d2f4d25ba95c25f50 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -262,10 +262,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + public CraftEntity getBukkitEntity() { + if (this.bukkitEntity == null) { +- this.bukkitEntity = CraftEntity.getEntity(this.level.getCraftServer(), this); ++ // Paper start - Folia schedulers ++ synchronized (this) { ++ if (this.bukkitEntity == null) { ++ return this.bukkitEntity = CraftEntity.getEntity(this.level.getCraftServer(), this); ++ } ++ } ++ // Paper end - Folia schedulers + } + return this.bukkitEntity; + } ++ // Paper start ++ public CraftEntity getBukkitEntityRaw() { ++ return this.bukkitEntity; ++ } ++ // Paper end + + // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() + public int getDefaultMaxAirSupply() { +@@ -4674,6 +4685,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public final void setRemoved(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { + CraftEventFactory.callEntityRemoveEvent(this, cause); + // CraftBukkit end ++ final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers + if (this.removalReason == null) { + this.removalReason = entity_removalreason; + } +@@ -4685,12 +4697,28 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.getPassengers().forEach(Entity::stopRiding); + this.levelCallback.onRemove(entity_removalreason); + this.onRemoval(entity_removalreason); ++ // Paper start - Folia schedulers ++ if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { ++ // Players need to be special cased, because they are regularly removed from the world ++ this.retireScheduler(); ++ } ++ // Paper end - Folia schedulers + } + + public void unsetRemoved() { + this.removalReason = null; + } + ++ // Paper start - Folia schedulers ++ /** ++ * Invoked only when the entity is truly removed from the server, never to be added to any world. ++ */ ++ public final void retireScheduler() { ++ // we need to force create the bukkit entity so that the scheduler can be retired... ++ this.getBukkitEntity().taskScheduler.retire(); ++ } ++ // Paper end - Folia schedulers ++ + @Override + public void setLevelCallback(EntityInLevelCallback changeListener) { + this.levelCallback = changeListener; +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index a7b79c9ec51f037287fad609c29b240e2071f2f8..46807d5d94a0f90b230dfaf4d37378a3bfa21414 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -313,6 +313,76 @@ public final class CraftServer implements Server { + private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher(); // Paper + private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer; // Paper - Custom Potion Mixes + ++ // Paper start - Folia region threading API ++ private final io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler(); ++ private final io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler asyncScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler(); ++ private final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler globalRegionScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler(); ++ ++ @Override ++ public final io.papermc.paper.threadedregions.scheduler.RegionScheduler getRegionScheduler() { ++ return this.regionizedScheduler; ++ } ++ ++ @Override ++ public final io.papermc.paper.threadedregions.scheduler.AsyncScheduler getAsyncScheduler() { ++ return this.asyncScheduler; ++ } ++ ++ @Override ++ public final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler getGlobalRegionScheduler() { ++ return this.globalRegionScheduler; ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(World world, io.papermc.paper.math.Position position) { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( ++ ((CraftWorld) world).getHandle(), position.blockX() >> 4, position.blockZ() >> 4 ++ ); ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(World world, io.papermc.paper.math.Position position, int squareRadiusChunks) { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( ++ ((CraftWorld) world).getHandle(), position.blockX() >> 4, position.blockZ() >> 4, squareRadiusChunks ++ ); ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(Location location) { ++ World world = location.getWorld(); ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( ++ ((CraftWorld) world).getHandle(), location.getBlockX() >> 4, location.getBlockZ() >> 4 ++ ); ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(Location location, int squareRadiusChunks) { ++ World world = location.getWorld(); ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( ++ ((CraftWorld) world).getHandle(), location.getBlockX() >> 4, location.getBlockZ() >> 4, squareRadiusChunks ++ ); ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(World world, int chunkX, int chunkZ) { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( ++ ((CraftWorld) world).getHandle(), chunkX, chunkZ ++ ); ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(World world, int chunkX, int chunkZ, int squareRadiusChunks) { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( ++ ((CraftWorld) world).getHandle(), chunkX, chunkZ, squareRadiusChunks ++ ); ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(Entity entity) { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandleRaw()); ++ } ++ // Paper end - Folia reagion threading API ++ + static { + ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); + ConfigurationSerialization.registerClass(CraftPlayerProfile.class); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 4209434ff066670000dadb0c59fea297f03300f4..df199c1cffa7795126ab83af67e184238ddb211d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -71,6 +71,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + private EntityDamageEvent lastDamageEvent; + private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY); + protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers ++ // Paper start - Folia shedulers ++ public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this); ++ private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this); ++ ++ @Override ++ public final io.papermc.paper.threadedregions.scheduler.EntityScheduler getScheduler() { ++ return this.apiScheduler; ++ }; ++ // Paper end - Folia schedulers + + public CraftEntity(final CraftServer server, final Entity entity) { + this.server = server; +@@ -487,6 +496,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return this.entity; + } + ++ // Paper start ++ public Entity getHandleRaw() { ++ return this.entity; ++ } ++ // Paper end ++ + @Override + public final EntityType getType() { + return this.entityType; diff --git a/patches/server/0835-Implement-PlayerFailMoveEvent.patch b/patches/server/0835-Implement-PlayerFailMoveEvent.patch deleted file mode 100644 index 19858740af..0000000000 --- a/patches/server/0835-Implement-PlayerFailMoveEvent.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Moulberry -Date: Wed, 26 Jul 2023 20:13:31 +0800 -Subject: [PATCH] Implement PlayerFailMoveEvent - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 60d58622fd568932c019ba6a4e4070a881fdda53..368547270a3e6cdbda812fcf0ed2519d71383b81 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1271,8 +1271,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - double d0 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX(this.player.getX())); final double toX = d0; // Paper - OBFHELPER - double d1 = ServerGamePacketListenerImpl.clampVertical(packet.getY(this.player.getY())); final double toY = d1; // Paper - OBFHELPER - double d2 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ(this.player.getZ())); final double toZ = d2; // Paper - OBFHELPER -- float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot())); -- float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot())); -+ float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot())); final float toYaw = f; // Paper - OBFHELPER -+ float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot())); final float toPitch = f1; // Paper - OBFHELPER - - if (this.player.isPassenger()) { - this.player.absMoveTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); -@@ -1339,8 +1339,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - // Paper start - Prevent moving into unloaded chunks - if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (this.player.getX() != toX || this.player.getZ() != toZ) && !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position())))) { -- this.internalTeleport(PositionMoveRotation.of(this.player), Collections.emptySet()); -- return; -+ // Paper start - Add fail move event -+ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_INTO_UNLOADED_CHUNK, -+ toX, toY, toZ, toYaw, toPitch, false); -+ if (!event.isAllowed()) { -+ this.internalTeleport(PositionMoveRotation.of(this.player), Collections.emptySet()); -+ return; -+ } -+ // Paper end - Add fail move event - } - // Paper end - Prevent moving into unloaded chunks - -@@ -1349,9 +1355,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - if (d10 - d9 > Math.max(f2, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2))) { - // CraftBukkit end -- ServerGamePacketListenerImpl.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); -- this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); -- return; -+ // Paper start - Add fail move event -+ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY, -+ toX, toY, toZ, toYaw, toPitch, true); -+ if (!event.isAllowed()) { -+ if (event.getLogWarning()) -+ ServerGamePacketListenerImpl.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); -+ this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); -+ return; -+ } -+ // Paper end - Add fail move event - } - } - } -@@ -1413,14 +1426,31 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - d8 = d2 - this.player.getZ(); - d10 = d6 * d6 + d7 * d7 + d8 * d8; -- boolean flag3 = false; -+ boolean movedWrongly = false; // Paper - Add fail move event; rename - - if (!this.player.isChangingDimension() && d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot -- flag3 = true; -+ // Paper start - Add fail move event -+ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_WRONGLY, -+ toX, toY, toZ, toYaw, toPitch, true); -+ if (!event.isAllowed()) { -+ movedWrongly = true; -+ if (event.getLogWarning()) -+ // Paper end - ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); -+ } // Paper - } - -- if (!this.player.noPhysics && !this.player.isSleeping() && (flag3 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2))) { -+ // Paper start - Add fail move event -+ boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2)); -+ if (teleportBack) { -+ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK, -+ toX, toY, toZ, toYaw, toPitch, false); -+ if (event.isAllowed()) { -+ teleportBack = false; -+ } -+ } -+ if (teleportBack) { -+ // Paper end - Add fail move event - this.internalTeleport(d3, d4, d5, f, f1); // 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. - this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packet.isOnGround()); - } else { -@@ -3537,4 +3567,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand); - } -+ -+ // Paper start - Add fail move event -+ private io.papermc.paper.event.player.PlayerFailMoveEvent fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason failReason, -+ double toX, double toY, double toZ, float toYaw, float toPitch, boolean logWarning) { -+ Player player = this.getCraftPlayer(); -+ Location from = new Location(player.getWorld(), this.lastPosX, this.lastPosY, this.lastPosZ, this.lastYaw, this.lastPitch); -+ Location to = new Location(player.getWorld(), toX, toY, toZ, toYaw, toPitch); -+ io.papermc.paper.event.player.PlayerFailMoveEvent event = new io.papermc.paper.event.player.PlayerFailMoveEvent(player, failReason, -+ false, logWarning, from, to); -+ event.callEvent(); -+ return event; -+ } -+ // Paper end - Add fail move event - } diff --git a/patches/server/0836-Folia-scheduler-and-owned-region-API.patch b/patches/server/0836-Folia-scheduler-and-owned-region-API.patch deleted file mode 100644 index 33561d0d1f..0000000000 --- a/patches/server/0836-Folia-scheduler-and-owned-region-API.patch +++ /dev/null @@ -1,1364 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 17 Jun 2023 11:52:52 +0200 -Subject: [PATCH] Folia scheduler and owned region API - -Pulling Folia API to Paper is primarily intended for plugins -that want to target both Paper and Folia without unnecessary -compatibility layers. - -Add both a location based scheduler, an entity based scheduler, -and a global region scheduler. - -Owned region API may be useful for plugins which want to perform -operations over large areas outside of the buffer zone provided -by the regionaliser, as it is not guaranteed that anything -outside of the buffer zone is owned. Then, the plugins may use -the schedulers depending on the result of the ownership check. - -diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -index d2dee700f2c5cc7d6a272e751a933901fe7a55b6..834b85f24df023642f8abf7213fe578ac8c17a3e 100644 ---- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -@@ -263,6 +263,22 @@ class PaperPluginInstanceManager { - + pluginName + " (Is it up to date?)", ex, plugin); // Paper - } - -+ // Paper start - Folia schedulers -+ try { -+ this.server.getGlobalRegionScheduler().cancelTasks(plugin); -+ } catch (Throwable ex) { -+ this.handlePluginException("Error occurred (in the plugin loader) while cancelling global tasks for " -+ + pluginName + " (Is it up to date?)", ex, plugin); // Paper -+ } -+ -+ try { -+ this.server.getAsyncScheduler().cancelTasks(plugin); -+ } catch (Throwable ex) { -+ this.handlePluginException("Error occurred (in the plugin loader) while cancelling async tasks for " -+ + pluginName + " (Is it up to date?)", ex, plugin); // Paper -+ } -+ // Paper end - Folia schedulers -+ - try { - this.server.getServicesManager().unregisterAll(plugin); - } catch (Throwable ex) { -diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c03608fec96b51e1867f43d8f42e5aefb1520e46 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java -@@ -0,0 +1,181 @@ -+package io.papermc.paper.threadedregions; -+ -+import ca.spottedleaf.concurrentutil.util.Validate; -+import ca.spottedleaf.moonrise.common.util.TickThread; -+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import net.minecraft.world.entity.Entity; -+import org.bukkit.craftbukkit.entity.CraftEntity; -+ -+import java.util.ArrayDeque; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.function.Consumer; -+ -+/** -+ * An entity can move between worlds with an arbitrary tick delay, be temporarily removed -+ * for players (i.e end credits), be partially removed from world state (i.e inactive but not removed), -+ * teleport between ticking regions, teleport between worlds (which will change the underlying Entity object -+ * for non-players), and even be removed entirely from the server. The uncertainty of an entity's state can make -+ * it difficult to schedule tasks without worrying about undefined behaviors resulting from any of the states listed -+ * previously. -+ * -+ *

-+ * This class is designed to eliminate those states by providing an interface to run tasks only when an entity -+ * is contained in a world, on the owning thread for the region, and by providing the current Entity object. -+ * The scheduler also allows a task to provide a callback, the "retired" callback, that will be invoked -+ * if the entity is removed before a task that was scheduled could be executed. The scheduler is also -+ * completely thread-safe, allowing tasks to be scheduled from any thread context. The scheduler also indicates -+ * properly whether a task was scheduled successfully (i.e scheduler not retired), thus the code scheduling any task -+ * knows whether the given callbacks will be invoked eventually or not - which may be critical for off-thread -+ * contexts. -+ *

-+ */ -+public final class EntityScheduler { -+ -+ /** -+ * The Entity. Note that it is the CraftEntity, since only that class properly tracks world transfers. -+ */ -+ public final CraftEntity entity; -+ -+ private static final record ScheduledTask(Consumer run, Consumer retired) {} -+ -+ private long tickCount = 0L; -+ private static final long RETIRED_TICK_COUNT = -1L; -+ private final Object stateLock = new Object(); -+ private final Long2ObjectOpenHashMap> oneTimeDelayed = new Long2ObjectOpenHashMap<>(); -+ -+ private final ArrayDeque currentlyExecuting = new ArrayDeque<>(); -+ -+ public EntityScheduler(final CraftEntity entity) { -+ this.entity = Validate.notNull(entity); -+ } -+ -+ /** -+ * Retires the scheduler, preventing new tasks from being scheduled and invoking the retired callback -+ * on all currently scheduled tasks. -+ * -+ *

-+ * Note: This should only be invoked after synchronously removing the entity from the world. -+ *

-+ * -+ * @throws IllegalStateException If the scheduler is already retired. -+ */ -+ public void retire() { -+ synchronized (this.stateLock) { -+ if (this.tickCount == RETIRED_TICK_COUNT) { -+ throw new IllegalStateException("Already retired"); -+ } -+ this.tickCount = RETIRED_TICK_COUNT; -+ } -+ -+ final Entity thisEntity = this.entity.getHandleRaw(); -+ -+ // correctly handle and order retiring while running executeTick -+ for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) { -+ final ScheduledTask task = this.currentlyExecuting.pollFirst(); -+ final Consumer retireTask = (Consumer)task.retired; -+ if (retireTask == null) { -+ continue; -+ } -+ -+ retireTask.accept(thisEntity); -+ } -+ -+ for (final List tasks : this.oneTimeDelayed.values()) { -+ for (int i = 0, len = tasks.size(); i < len; ++i) { -+ final ScheduledTask task = tasks.get(i); -+ final Consumer retireTask = (Consumer)task.retired; -+ if (retireTask == null) { -+ continue; -+ } -+ -+ retireTask.accept(thisEntity); -+ } -+ } -+ } -+ -+ /** -+ * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity -+ * removed), then returns {@code false}. Otherwise, either the run callback will be invoked after the specified delay, -+ * or the retired callback will be invoked if the scheduler is retired. -+ * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove -+ * other entities, load chunks, load worlds, modify ticket levels, etc. -+ * -+ *

-+ * It is guaranteed that the run and retired callback are invoked on the region which owns the entity. -+ *

-+ *

-+ * The run and retired callback take an Entity parameter representing the current object entity that the scheduler -+ * is tied to. Since the scheduler is transferred when an entity changes dimensions, it is possible the entity parameter -+ * is not the same when the task was first scheduled. Thus, only the parameter provided should be used. -+ *

-+ * @param run The callback to run after the specified delay, may not be null. -+ * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. -+ * @param delay The delay in ticks before the run callback is invoked. Any value less-than 1 is treated as 1. -+ * @return {@code true} if the task was scheduled, which means that either the run function or the retired function -+ * will be invoked (but never both), or {@code false} indicating neither the run nor retired function will be invoked -+ * since the scheduler has been retired. -+ */ -+ public boolean schedule(final Consumer run, final Consumer retired, final long delay) { -+ Validate.notNull(run, "Run task may not be null"); -+ -+ final ScheduledTask task = new ScheduledTask(run, retired); -+ synchronized (this.stateLock) { -+ if (this.tickCount == RETIRED_TICK_COUNT) { -+ return false; -+ } -+ this.oneTimeDelayed.computeIfAbsent(this.tickCount + Math.max(1L, delay), (final long keyInMap) -> { -+ return new ArrayList<>(); -+ }).add(task); -+ } -+ -+ return true; -+ } -+ -+ /** -+ * Executes a tick for the scheduler. -+ * -+ * @throws IllegalStateException If the scheduler is retired. -+ */ -+ public void executeTick() { -+ final Entity thisEntity = this.entity.getHandleRaw(); -+ -+ TickThread.ensureTickThread(thisEntity, "May not tick entity scheduler asynchronously"); -+ final List toRun; -+ synchronized (this.stateLock) { -+ if (this.tickCount == RETIRED_TICK_COUNT) { -+ throw new IllegalStateException("Ticking retired scheduler"); -+ } -+ ++this.tickCount; -+ if (this.oneTimeDelayed.isEmpty()) { -+ toRun = null; -+ } else { -+ toRun = this.oneTimeDelayed.remove(this.tickCount); -+ } -+ } -+ -+ if (toRun != null) { -+ for (int i = 0, len = toRun.size(); i < len; ++i) { -+ this.currentlyExecuting.addLast(toRun.get(i)); -+ } -+ } -+ -+ // Note: It is allowed for the tasks executed to retire the entity in a given task. -+ for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) { -+ if (!TickThread.isTickThreadFor(thisEntity)) { -+ // tp has been queued sync by one of the tasks -+ // in this case, we need to delay the tasks for next tick -+ break; -+ } -+ final ScheduledTask task = this.currentlyExecuting.pollFirst(); -+ -+ if (this.tickCount != RETIRED_TICK_COUNT) { -+ ((Consumer)task.run).accept(thisEntity); -+ } else { -+ // retired synchronously -+ // note: here task is null -+ break; -+ } -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FallbackRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FallbackRegionScheduler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..94056d61a304ee012ae1828a33412516095f996f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FallbackRegionScheduler.java -@@ -0,0 +1,30 @@ -+package io.papermc.paper.threadedregions.scheduler; -+ -+import org.bukkit.World; -+import org.bukkit.plugin.Plugin; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.function.Consumer; -+ -+public final class FallbackRegionScheduler implements RegionScheduler { -+ -+ @Override -+ public void execute(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Runnable run) { -+ plugin.getServer().getGlobalRegionScheduler().execute(plugin, run); -+ } -+ -+ @Override -+ public @NotNull ScheduledTask run(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Consumer task) { -+ return plugin.getServer().getGlobalRegionScheduler().run(plugin, task); -+ } -+ -+ @Override -+ public @NotNull ScheduledTask runDelayed(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Consumer task, final long delayTicks) { -+ return plugin.getServer().getGlobalRegionScheduler().runDelayed(plugin, task, delayTicks); -+ } -+ -+ @Override -+ public @NotNull ScheduledTask runAtFixedRate(@NotNull final Plugin plugin, @NotNull final World world, final int chunkX, final int chunkZ, @NotNull final Consumer task, final long initialDelayTicks, final long periodTicks) { -+ return plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, task, initialDelayTicks, periodTicks); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaAsyncScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaAsyncScheduler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..374abffb9f1ce1a308822aed13038e77fe9ca08b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaAsyncScheduler.java -@@ -0,0 +1,328 @@ -+package io.papermc.paper.threadedregions.scheduler; -+ -+import ca.spottedleaf.concurrentutil.util.Validate; -+import com.mojang.logging.LogUtils; -+import org.bukkit.plugin.IllegalPluginAccessException; -+import org.bukkit.plugin.Plugin; -+import org.slf4j.Logger; -+ -+import java.util.Set; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.concurrent.Executor; -+import java.util.concurrent.Executors; -+import java.util.concurrent.ScheduledExecutorService; -+import java.util.concurrent.ScheduledFuture; -+import java.util.concurrent.SynchronousQueue; -+import java.util.concurrent.ThreadFactory; -+import java.util.concurrent.ThreadPoolExecutor; -+import java.util.concurrent.TimeUnit; -+import java.util.concurrent.atomic.AtomicInteger; -+import java.util.function.Consumer; -+import java.util.logging.Level; -+ -+public final class FoliaAsyncScheduler implements AsyncScheduler { -+ -+ private static final Logger LOGGER = LogUtils.getClassLogger(); -+ -+ private final Executor executors = new ThreadPoolExecutor(Math.max(4, Runtime.getRuntime().availableProcessors() / 2), Integer.MAX_VALUE, -+ 30L, TimeUnit.SECONDS, new SynchronousQueue<>(), -+ new ThreadFactory() { -+ private final AtomicInteger idGenerator = new AtomicInteger(); -+ -+ @Override -+ public Thread newThread(final Runnable run) { -+ final Thread ret = new Thread(run); -+ -+ ret.setName("Folia Async Scheduler Thread #" + this.idGenerator.getAndIncrement()); -+ ret.setPriority(Thread.NORM_PRIORITY - 1); -+ ret.setUncaughtExceptionHandler((final Thread thread, final Throwable thr) -> { -+ LOGGER.error("Uncaught exception in thread: " + thread.getName(), thr); -+ }); -+ -+ return ret; -+ } -+ } -+ ); -+ -+ private final ScheduledExecutorService timerThread = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { -+ @Override -+ public Thread newThread(final Runnable run) { -+ final Thread ret = new Thread(run); -+ -+ ret.setName("Folia Async Scheduler Thread Timer"); -+ ret.setPriority(Thread.NORM_PRIORITY + 1); -+ ret.setUncaughtExceptionHandler((final Thread thread, final Throwable thr) -> { -+ LOGGER.error("Uncaught exception in thread: " + thread.getName(), thr); -+ }); -+ -+ return ret; -+ } -+ }); -+ -+ private final Set tasks = ConcurrentHashMap.newKeySet(); -+ -+ @Override -+ public ScheduledTask runNow(final Plugin plugin, final Consumer task) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(task, "Task may not be null"); -+ -+ if (!plugin.isEnabled()) { -+ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); -+ } -+ -+ final AsyncScheduledTask ret = new AsyncScheduledTask(plugin, -1L, task, null, -1L); -+ -+ this.tasks.add(ret); -+ this.executors.execute(ret); -+ -+ if (!plugin.isEnabled()) { -+ // handle race condition where plugin is disabled asynchronously -+ ret.cancel(); -+ } -+ -+ return ret; -+ } -+ -+ @Override -+ public ScheduledTask runDelayed(final Plugin plugin, final Consumer task, final long delay, -+ final TimeUnit unit) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(task, "Task may not be null"); -+ Validate.notNull(unit, "Time unit may not be null"); -+ if (delay < 0L) { -+ throw new IllegalArgumentException("Delay may not be < 0"); -+ } -+ -+ if (!plugin.isEnabled()) { -+ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); -+ } -+ -+ return this.scheduleTimerTask(plugin, task, delay, -1L, unit); -+ } -+ -+ @Override -+ public ScheduledTask runAtFixedRate(final Plugin plugin, final Consumer task, final long initialDelay, -+ final long period, final TimeUnit unit) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(task, "Task may not be null"); -+ Validate.notNull(unit, "Time unit may not be null"); -+ if (initialDelay < 0L) { -+ throw new IllegalArgumentException("Initial delay may not be < 0"); -+ } -+ if (period <= 0L) { -+ throw new IllegalArgumentException("Period may not be <= 0"); -+ } -+ -+ if (!plugin.isEnabled()) { -+ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); -+ } -+ -+ return this.scheduleTimerTask(plugin, task, initialDelay, period, unit); -+ } -+ -+ private AsyncScheduledTask scheduleTimerTask(final Plugin plugin, final Consumer task, final long initialDelay, -+ final long period, final TimeUnit unit) { -+ final AsyncScheduledTask ret = new AsyncScheduledTask( -+ plugin, period <= 0 ? period : unit.toNanos(period), task, null, -+ System.nanoTime() + unit.toNanos(initialDelay) -+ ); -+ -+ synchronized (ret) { -+ // even though ret is not published, we need to synchronise while scheduling to avoid a race condition -+ // for when a scheduled task immediately executes before we update the delay field and state field -+ ret.setDelay(this.timerThread.schedule(ret, initialDelay, unit)); -+ this.tasks.add(ret); -+ } -+ -+ if (!plugin.isEnabled()) { -+ // handle race condition where plugin is disabled asynchronously -+ ret.cancel(); -+ } -+ -+ return ret; -+ } -+ -+ @Override -+ public void cancelTasks(final Plugin plugin) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ -+ for (final AsyncScheduledTask task : this.tasks) { -+ if (task.plugin == plugin) { -+ task.cancel(); -+ } -+ } -+ } -+ -+ private final class AsyncScheduledTask implements ScheduledTask, Runnable { -+ -+ private static final int STATE_ON_TIMER = 0; -+ private static final int STATE_SCHEDULED_EXECUTOR = 1; -+ private static final int STATE_EXECUTING = 2; -+ private static final int STATE_EXECUTING_CANCELLED = 3; -+ private static final int STATE_FINISHED = 4; -+ private static final int STATE_CANCELLED = 5; -+ -+ private final Plugin plugin; -+ private final long repeatDelay; // in ns -+ private Consumer run; -+ private ScheduledFuture delay; -+ private int state; -+ private long scheduleTarget; -+ -+ public AsyncScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer run, -+ final ScheduledFuture delay, final long firstTarget) { -+ this.plugin = plugin; -+ this.repeatDelay = repeatDelay; -+ this.run = run; -+ this.delay = delay; -+ this.state = delay == null ? STATE_SCHEDULED_EXECUTOR : STATE_ON_TIMER; -+ this.scheduleTarget = firstTarget; -+ } -+ -+ private void setDelay(final ScheduledFuture delay) { -+ this.delay = delay; -+ this.state = STATE_SCHEDULED_EXECUTOR; -+ } -+ -+ @Override -+ public void run() { -+ final boolean repeating = this.isRepeatingTask(); -+ // try to advance state -+ final boolean timer; -+ synchronized (this) { -+ if (this.state == STATE_ON_TIMER) { -+ timer = true; -+ this.delay = null; -+ this.state = STATE_SCHEDULED_EXECUTOR; -+ } else if (this.state != STATE_SCHEDULED_EXECUTOR) { -+ // cancelled -+ if (this.state != STATE_CANCELLED) { -+ throw new IllegalStateException("Wrong state: " + this.state); -+ } -+ return; -+ } else { -+ timer = false; -+ this.state = STATE_EXECUTING; -+ } -+ } -+ -+ if (timer) { -+ // the scheduled executor is single thread, and unfortunately not expandable with threads -+ // so we just schedule onto the executor -+ FoliaAsyncScheduler.this.executors.execute(this); -+ return; -+ } -+ -+ try { -+ this.run.accept(this); -+ } catch (final Throwable throwable) { -+ this.plugin.getLogger().log(Level.WARNING, "Async task for " + this.plugin.getDescription().getFullName() + " generated an exception", throwable); -+ } finally { -+ boolean removeFromTasks = false; -+ synchronized (this) { -+ if (!repeating) { -+ // only want to execute once, so we're done -+ removeFromTasks = true; -+ this.state = STATE_FINISHED; -+ } else if (this.state != STATE_EXECUTING_CANCELLED) { -+ this.state = STATE_ON_TIMER; -+ // account for any delays, whether it be by task exec. or scheduler issues so that we keep -+ // the fixed schedule -+ final long currTime = System.nanoTime(); -+ final long delay = Math.max(0L, this.scheduleTarget + this.repeatDelay - currTime); -+ this.scheduleTarget = currTime + delay; -+ this.delay = FoliaAsyncScheduler.this.timerThread.schedule(this, delay, TimeUnit.NANOSECONDS); -+ } else { -+ // cancelled repeating task -+ removeFromTasks = true; -+ } -+ } -+ -+ if (removeFromTasks) { -+ this.run = null; -+ FoliaAsyncScheduler.this.tasks.remove(this); -+ } -+ } -+ } -+ -+ @Override -+ public Plugin getOwningPlugin() { -+ return this.plugin; -+ } -+ -+ @Override -+ public boolean isRepeatingTask() { -+ return this.repeatDelay > 0L; -+ } -+ -+ @Override -+ public CancelledState cancel() { -+ ScheduledFuture delay = null; -+ CancelledState ret; -+ synchronized (this) { -+ switch (this.state) { -+ case STATE_ON_TIMER: { -+ delay = this.delay; -+ this.delay = null; -+ this.state = STATE_CANCELLED; -+ ret = CancelledState.CANCELLED_BY_CALLER; -+ break; -+ } -+ case STATE_SCHEDULED_EXECUTOR: { -+ this.state = STATE_CANCELLED; -+ ret = CancelledState.CANCELLED_BY_CALLER; -+ break; -+ } -+ case STATE_EXECUTING: { -+ if (!this.isRepeatingTask()) { -+ return CancelledState.RUNNING; -+ } -+ this.state = STATE_EXECUTING_CANCELLED; -+ return CancelledState.NEXT_RUNS_CANCELLED; -+ } -+ case STATE_EXECUTING_CANCELLED: { -+ return CancelledState.NEXT_RUNS_CANCELLED_ALREADY; -+ } -+ case STATE_FINISHED: { -+ return CancelledState.ALREADY_EXECUTED; -+ } -+ case STATE_CANCELLED: { -+ return CancelledState.CANCELLED_ALREADY; -+ } -+ default: { -+ throw new IllegalStateException("Unknown state: " + this.state); -+ } -+ } -+ } -+ -+ if (delay != null) { -+ delay.cancel(false); -+ } -+ this.run = null; -+ FoliaAsyncScheduler.this.tasks.remove(this); -+ return ret; -+ } -+ -+ @Override -+ public ExecutionState getExecutionState() { -+ synchronized (this) { -+ switch (this.state) { -+ case STATE_ON_TIMER: -+ case STATE_SCHEDULED_EXECUTOR: -+ return ExecutionState.IDLE; -+ case STATE_EXECUTING: -+ return ExecutionState.RUNNING; -+ case STATE_EXECUTING_CANCELLED: -+ return ExecutionState.CANCELLED_RUNNING; -+ case STATE_FINISHED: -+ return ExecutionState.FINISHED; -+ case STATE_CANCELLED: -+ return ExecutionState.CANCELLED; -+ default: { -+ throw new IllegalStateException("Unknown state: " + this.state); -+ } -+ } -+ } -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaEntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaEntityScheduler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..011754962896e32f51ed4606dcbea18a430a2bc1 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaEntityScheduler.java -@@ -0,0 +1,268 @@ -+package io.papermc.paper.threadedregions.scheduler; -+ -+import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; -+import ca.spottedleaf.concurrentutil.util.Validate; -+import net.minecraft.world.entity.Entity; -+import org.bukkit.craftbukkit.entity.CraftEntity; -+import org.bukkit.plugin.IllegalPluginAccessException; -+import org.bukkit.plugin.Plugin; -+import org.jetbrains.annotations.Nullable; -+ -+import java.lang.invoke.VarHandle; -+import java.util.function.Consumer; -+import java.util.logging.Level; -+ -+public final class FoliaEntityScheduler implements EntityScheduler { -+ -+ private final CraftEntity entity; -+ -+ public FoliaEntityScheduler(final CraftEntity entity) { -+ this.entity = entity; -+ } -+ -+ private static Consumer wrap(final Plugin plugin, final Runnable runnable) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(runnable, "Runnable may not be null"); -+ -+ return (final Entity nmsEntity) -> { -+ if (!plugin.isEnabled()) { -+ // don't execute if the plugin is disabled -+ return; -+ } -+ try { -+ runnable.run(); -+ } catch (final Throwable throwable) { -+ plugin.getLogger().log(Level.WARNING, "Entity task for " + plugin.getDescription().getFullName() + " generated an exception", throwable); -+ } -+ }; -+ } -+ -+ @Override -+ public boolean execute(final Plugin plugin, final Runnable run, final Runnable retired, -+ final long delay) { -+ final Consumer runNMS = wrap(plugin, run); -+ final Consumer runRetired = retired == null ? null : wrap(plugin, retired); -+ -+ return this.entity.taskScheduler.schedule(runNMS, runRetired, delay); -+ } -+ -+ @Override -+ public @Nullable ScheduledTask run(final Plugin plugin, final Consumer task, final Runnable retired) { -+ return this.runDelayed(plugin, task, retired, 1); -+ } -+ -+ @Override -+ public @Nullable ScheduledTask runDelayed(final Plugin plugin, final Consumer task, final Runnable retired, -+ final long delayTicks) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(task, "Task may not be null"); -+ if (delayTicks <= 0) { -+ throw new IllegalArgumentException("Delay ticks may not be <= 0"); -+ } -+ -+ if (!plugin.isEnabled()) { -+ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); -+ } -+ -+ final EntityScheduledTask ret = new EntityScheduledTask(plugin, -1, task, retired); -+ -+ if (!this.scheduleInternal(ret, delayTicks)) { -+ return null; -+ } -+ -+ if (!plugin.isEnabled()) { -+ // handle race condition where plugin is disabled asynchronously -+ ret.cancel(); -+ } -+ -+ return ret; -+ } -+ -+ @Override -+ public @Nullable ScheduledTask runAtFixedRate(final Plugin plugin, final Consumer task, -+ final Runnable retired, final long initialDelayTicks, final long periodTicks) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(task, "Task may not be null"); -+ if (initialDelayTicks <= 0) { -+ throw new IllegalArgumentException("Initial delay ticks may not be <= 0"); -+ } -+ if (periodTicks <= 0) { -+ throw new IllegalArgumentException("Period ticks may not be <= 0"); -+ } -+ -+ if (!plugin.isEnabled()) { -+ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); -+ } -+ -+ final EntityScheduledTask ret = new EntityScheduledTask(plugin, periodTicks, task, retired); -+ -+ if (!this.scheduleInternal(ret, initialDelayTicks)) { -+ return null; -+ } -+ -+ if (!plugin.isEnabled()) { -+ // handle race condition where plugin is disabled asynchronously -+ ret.cancel(); -+ } -+ -+ return ret; -+ } -+ -+ private boolean scheduleInternal(final EntityScheduledTask ret, final long delay) { -+ return this.entity.taskScheduler.schedule(ret, ret, delay); -+ } -+ -+ private final class EntityScheduledTask implements ScheduledTask, Consumer { -+ -+ private static final int STATE_IDLE = 0; -+ private static final int STATE_EXECUTING = 1; -+ private static final int STATE_EXECUTING_CANCELLED = 2; -+ private static final int STATE_FINISHED = 3; -+ private static final int STATE_CANCELLED = 4; -+ -+ private final Plugin plugin; -+ private final long repeatDelay; // in ticks -+ private Consumer run; -+ private Runnable retired; -+ private volatile int state; -+ -+ private static final VarHandle STATE_HANDLE = ConcurrentUtil.getVarHandle(EntityScheduledTask.class, "state", int.class); -+ -+ private EntityScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer run, final Runnable retired) { -+ this.plugin = plugin; -+ this.repeatDelay = repeatDelay; -+ this.run = run; -+ this.retired = retired; -+ } -+ -+ private final int getStateVolatile() { -+ return (int)STATE_HANDLE.get(this); -+ } -+ -+ private final int compareAndExchangeStateVolatile(final int expect, final int update) { -+ return (int)STATE_HANDLE.compareAndExchange(this, expect, update); -+ } -+ -+ private final void setStateVolatile(final int value) { -+ STATE_HANDLE.setVolatile(this, value); -+ } -+ -+ @Override -+ public void accept(final Entity entity) { -+ if (!this.plugin.isEnabled()) { -+ // don't execute if the plugin is disabled -+ this.setStateVolatile(STATE_CANCELLED); -+ return; -+ } -+ -+ final boolean repeating = this.isRepeatingTask(); -+ if (STATE_IDLE != this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_EXECUTING)) { -+ // cancelled -+ return; -+ } -+ -+ final boolean retired = entity.isRemoved(); -+ -+ try { -+ if (!retired) { -+ this.run.accept(this); -+ } else { -+ if (this.retired != null) { -+ this.retired.run(); -+ } -+ } -+ } catch (final Throwable throwable) { -+ this.plugin.getLogger().log(Level.WARNING, "Entity task for " + this.plugin.getDescription().getFullName() + " generated an exception", throwable); -+ } finally { -+ boolean reschedule = false; -+ if (!repeating && !retired) { -+ this.setStateVolatile(STATE_FINISHED); -+ } else if (retired || !this.plugin.isEnabled()) { -+ this.setStateVolatile(STATE_CANCELLED); -+ } else if (STATE_EXECUTING == this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_IDLE)) { -+ reschedule = true; -+ } // else: cancelled repeating task -+ -+ if (!reschedule) { -+ this.run = null; -+ this.retired = null; -+ } else { -+ if (!FoliaEntityScheduler.this.scheduleInternal(this, this.repeatDelay)) { -+ // the task itself must have removed the entity, so in this case we need to mark as cancelled -+ this.setStateVolatile(STATE_CANCELLED); -+ } -+ } -+ } -+ } -+ -+ @Override -+ public Plugin getOwningPlugin() { -+ return this.plugin; -+ } -+ -+ @Override -+ public boolean isRepeatingTask() { -+ return this.repeatDelay > 0; -+ } -+ -+ @Override -+ public CancelledState cancel() { -+ for (int curr = this.getStateVolatile();;) { -+ switch (curr) { -+ case STATE_IDLE: { -+ if (STATE_IDLE == (curr = this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_CANCELLED))) { -+ this.state = STATE_CANCELLED; -+ this.run = null; -+ this.retired = null; -+ return CancelledState.CANCELLED_BY_CALLER; -+ } -+ // try again -+ continue; -+ } -+ case STATE_EXECUTING: { -+ if (!this.isRepeatingTask()) { -+ return CancelledState.RUNNING; -+ } -+ if (STATE_EXECUTING == (curr = this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_EXECUTING_CANCELLED))) { -+ return CancelledState.NEXT_RUNS_CANCELLED; -+ } -+ // try again -+ continue; -+ } -+ case STATE_EXECUTING_CANCELLED: { -+ return CancelledState.NEXT_RUNS_CANCELLED_ALREADY; -+ } -+ case STATE_FINISHED: { -+ return CancelledState.ALREADY_EXECUTED; -+ } -+ case STATE_CANCELLED: { -+ return CancelledState.CANCELLED_ALREADY; -+ } -+ default: { -+ throw new IllegalStateException("Unknown state: " + curr); -+ } -+ } -+ } -+ } -+ -+ @Override -+ public ExecutionState getExecutionState() { -+ final int state = this.getStateVolatile(); -+ switch (state) { -+ case STATE_IDLE: -+ return ExecutionState.IDLE; -+ case STATE_EXECUTING: -+ return ExecutionState.RUNNING; -+ case STATE_EXECUTING_CANCELLED: -+ return ExecutionState.CANCELLED_RUNNING; -+ case STATE_FINISHED: -+ return ExecutionState.FINISHED; -+ case STATE_CANCELLED: -+ return ExecutionState.CANCELLED; -+ default: { -+ throw new IllegalStateException("Unknown state: " + state); -+ } -+ } -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d306f911757a4d556c82c0070d4837db87afc497 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java -@@ -0,0 +1,267 @@ -+package io.papermc.paper.threadedregions.scheduler; -+ -+import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; -+import ca.spottedleaf.concurrentutil.util.Validate; -+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import org.bukkit.plugin.IllegalPluginAccessException; -+import org.bukkit.plugin.Plugin; -+ -+import java.lang.invoke.VarHandle; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.function.Consumer; -+import java.util.logging.Level; -+ -+public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler { -+ -+ private long tickCount = 0L; -+ private final Object stateLock = new Object(); -+ private final Long2ObjectOpenHashMap> tasksByDeadline = new Long2ObjectOpenHashMap<>(); -+ -+ public void tick() { -+ final List run; -+ synchronized (this.stateLock) { -+ ++this.tickCount; -+ if (this.tasksByDeadline.isEmpty()) { -+ run = null; -+ } else { -+ run = this.tasksByDeadline.remove(this.tickCount); -+ } -+ } -+ -+ if (run == null) { -+ return; -+ } -+ -+ for (int i = 0, len = run.size(); i < len; ++i) { -+ run.get(i).run(); -+ } -+ } -+ -+ @Override -+ public void execute(final Plugin plugin, final Runnable run) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(run, "Runnable may not be null"); -+ -+ this.run(plugin, (final ScheduledTask task) -> { -+ run.run(); -+ }); -+ } -+ -+ @Override -+ public ScheduledTask run(final Plugin plugin, final Consumer task) { -+ return this.runDelayed(plugin, task, 1); -+ } -+ -+ @Override -+ public ScheduledTask runDelayed(final Plugin plugin, final Consumer task, final long delayTicks) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(task, "Task may not be null"); -+ if (delayTicks <= 0) { -+ throw new IllegalArgumentException("Delay ticks may not be <= 0"); -+ } -+ -+ if (!plugin.isEnabled()) { -+ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); -+ } -+ -+ final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, -1, task); -+ -+ this.scheduleInternal(ret, delayTicks); -+ -+ if (!plugin.isEnabled()) { -+ // handle race condition where plugin is disabled asynchronously -+ ret.cancel(); -+ } -+ -+ return ret; -+ } -+ -+ @Override -+ public ScheduledTask runAtFixedRate(final Plugin plugin, final Consumer task, final long initialDelayTicks, final long periodTicks) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ Validate.notNull(task, "Task may not be null"); -+ if (initialDelayTicks <= 0) { -+ throw new IllegalArgumentException("Initial delay ticks may not be <= 0"); -+ } -+ if (periodTicks <= 0) { -+ throw new IllegalArgumentException("Period ticks may not be <= 0"); -+ } -+ -+ if (!plugin.isEnabled()) { -+ throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); -+ } -+ -+ final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, periodTicks, task); -+ -+ this.scheduleInternal(ret, initialDelayTicks); -+ -+ if (!plugin.isEnabled()) { -+ // handle race condition where plugin is disabled asynchronously -+ ret.cancel(); -+ } -+ -+ return ret; -+ } -+ -+ @Override -+ public void cancelTasks(final Plugin plugin) { -+ Validate.notNull(plugin, "Plugin may not be null"); -+ -+ final List toCancel = new ArrayList<>(); -+ synchronized (this.stateLock) { -+ for (final List tasks : this.tasksByDeadline.values()) { -+ for (int i = 0, len = tasks.size(); i < len; ++i) { -+ final GlobalScheduledTask task = tasks.get(i); -+ if (task.plugin == plugin) { -+ toCancel.add(task); -+ } -+ } -+ } -+ } -+ -+ for (int i = 0, len = toCancel.size(); i < len; ++i) { -+ toCancel.get(i).cancel(); -+ } -+ } -+ -+ private void scheduleInternal(final GlobalScheduledTask task, final long delay) { -+ // note: delay > 0 -+ synchronized (this.stateLock) { -+ this.tasksByDeadline.computeIfAbsent(this.tickCount + delay, (final long keyInMap) -> { -+ return new ArrayList<>(); -+ }).add(task); -+ } -+ } -+ -+ private final class GlobalScheduledTask implements ScheduledTask, Runnable { -+ -+ private static final int STATE_IDLE = 0; -+ private static final int STATE_EXECUTING = 1; -+ private static final int STATE_EXECUTING_CANCELLED = 2; -+ private static final int STATE_FINISHED = 3; -+ private static final int STATE_CANCELLED = 4; -+ -+ private final Plugin plugin; -+ private final long repeatDelay; // in ticks -+ private Consumer run; -+ private volatile int state; -+ -+ private static final VarHandle STATE_HANDLE = ConcurrentUtil.getVarHandle(GlobalScheduledTask.class, "state", int.class); -+ -+ private GlobalScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer run) { -+ this.plugin = plugin; -+ this.repeatDelay = repeatDelay; -+ this.run = run; -+ } -+ -+ private final int getStateVolatile() { -+ return (int)STATE_HANDLE.get(this); -+ } -+ -+ private final int compareAndExchangeStateVolatile(final int expect, final int update) { -+ return (int)STATE_HANDLE.compareAndExchange(this, expect, update); -+ } -+ -+ private final void setStateVolatile(final int value) { -+ STATE_HANDLE.setVolatile(this, value); -+ } -+ -+ @Override -+ public void run() { -+ final boolean repeating = this.isRepeatingTask(); -+ if (STATE_IDLE != this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_EXECUTING)) { -+ // cancelled -+ return; -+ } -+ -+ try { -+ this.run.accept(this); -+ } catch (final Throwable throwable) { -+ this.plugin.getLogger().log(Level.WARNING, "Global task for " + this.plugin.getDescription().getFullName() + " generated an exception", throwable); -+ } finally { -+ boolean reschedule = false; -+ if (!repeating) { -+ this.setStateVolatile(STATE_FINISHED); -+ } else if (STATE_EXECUTING == this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_IDLE)) { -+ reschedule = true; -+ } // else: cancelled repeating task -+ -+ if (!reschedule) { -+ this.run = null; -+ } else { -+ FoliaGlobalRegionScheduler.this.scheduleInternal(this, this.repeatDelay); -+ } -+ } -+ } -+ -+ @Override -+ public Plugin getOwningPlugin() { -+ return this.plugin; -+ } -+ -+ @Override -+ public boolean isRepeatingTask() { -+ return this.repeatDelay > 0; -+ } -+ -+ @Override -+ public CancelledState cancel() { -+ for (int curr = this.getStateVolatile();;) { -+ switch (curr) { -+ case STATE_IDLE: { -+ if (STATE_IDLE == (curr = this.compareAndExchangeStateVolatile(STATE_IDLE, STATE_CANCELLED))) { -+ this.state = STATE_CANCELLED; -+ this.run = null; -+ return CancelledState.CANCELLED_BY_CALLER; -+ } -+ // try again -+ continue; -+ } -+ case STATE_EXECUTING: { -+ if (!this.isRepeatingTask()) { -+ return CancelledState.RUNNING; -+ } -+ if (STATE_EXECUTING == (curr = this.compareAndExchangeStateVolatile(STATE_EXECUTING, STATE_EXECUTING_CANCELLED))) { -+ return CancelledState.NEXT_RUNS_CANCELLED; -+ } -+ // try again -+ continue; -+ } -+ case STATE_EXECUTING_CANCELLED: { -+ return CancelledState.NEXT_RUNS_CANCELLED_ALREADY; -+ } -+ case STATE_FINISHED: { -+ return CancelledState.ALREADY_EXECUTED; -+ } -+ case STATE_CANCELLED: { -+ return CancelledState.CANCELLED_ALREADY; -+ } -+ default: { -+ throw new IllegalStateException("Unknown state: " + curr); -+ } -+ } -+ } -+ } -+ -+ @Override -+ public ExecutionState getExecutionState() { -+ final int state = this.getStateVolatile(); -+ switch (state) { -+ case STATE_IDLE: -+ return ExecutionState.IDLE; -+ case STATE_EXECUTING: -+ return ExecutionState.RUNNING; -+ case STATE_EXECUTING_CANCELLED: -+ return ExecutionState.CANCELLED_RUNNING; -+ case STATE_FINISHED: -+ return ExecutionState.FINISHED; -+ case STATE_CANCELLED: -+ return ExecutionState.CANCELLED; -+ default: { -+ throw new IllegalStateException("Unknown state: " + state); -+ } -+ } -+ } -+ } -+} -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 736ff3988d66b8694475d5f62673da61fcb76179..7e83a0de08488c5acf3c1a5d7107564e2a8ed7e0 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1655,6 +1655,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -+ for (final Entity entity : level.getEntities().getAll()) { -+ if (entity.isRemoved()) { -+ continue; -+ } -+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw(); -+ if (bukkit != null) { -+ bukkit.taskScheduler.executeTick(); -+ } -+ } -+ }); -+ // Paper end - Folia scheduler API - io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper - gameprofilerfiller.push("commandFunctions"); - MinecraftTimings.commandFunctionsTimer.startTiming(); // Spigot // Paper -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f9212fc2db00531da1618780e231e8ad21285907..a9063533ea4b2b349d476127b99c822203d7dfcb 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -598,6 +598,7 @@ public abstract class PlayerList { - } - - worldserver.removePlayerImmediately(entityplayer, Entity.RemovalReason.UNLOADED_WITH_PLAYER); -+ entityplayer.retireScheduler(); // Paper - Folia schedulers - entityplayer.getAdvancements().stopListening(); - this.players.remove(entityplayer); - this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 3444b1a2da80b85e2b1928d69ff0dd980c5fb34f..463dd4f91212318b51174c5d2f4d25ba95c25f50 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -262,10 +262,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - public CraftEntity getBukkitEntity() { - if (this.bukkitEntity == null) { -- this.bukkitEntity = CraftEntity.getEntity(this.level.getCraftServer(), this); -+ // Paper start - Folia schedulers -+ synchronized (this) { -+ if (this.bukkitEntity == null) { -+ return this.bukkitEntity = CraftEntity.getEntity(this.level.getCraftServer(), this); -+ } -+ } -+ // Paper end - Folia schedulers - } - return this.bukkitEntity; - } -+ // Paper start -+ public CraftEntity getBukkitEntityRaw() { -+ return this.bukkitEntity; -+ } -+ // Paper end - - // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() - public int getDefaultMaxAirSupply() { -@@ -4674,6 +4685,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public final void setRemoved(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { - CraftEventFactory.callEntityRemoveEvent(this, cause); - // CraftBukkit end -+ final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers - if (this.removalReason == null) { - this.removalReason = entity_removalreason; - } -@@ -4685,12 +4697,28 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.getPassengers().forEach(Entity::stopRiding); - this.levelCallback.onRemove(entity_removalreason); - this.onRemoval(entity_removalreason); -+ // Paper start - Folia schedulers -+ if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { -+ // Players need to be special cased, because they are regularly removed from the world -+ this.retireScheduler(); -+ } -+ // Paper end - Folia schedulers - } - - public void unsetRemoved() { - this.removalReason = null; - } - -+ // Paper start - Folia schedulers -+ /** -+ * Invoked only when the entity is truly removed from the server, never to be added to any world. -+ */ -+ public final void retireScheduler() { -+ // we need to force create the bukkit entity so that the scheduler can be retired... -+ this.getBukkitEntity().taskScheduler.retire(); -+ } -+ // Paper end - Folia schedulers -+ - @Override - public void setLevelCallback(EntityInLevelCallback changeListener) { - this.levelCallback = changeListener; -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 1310bdd5ced5941b2ab4ed1f15365722c0b8252d..0193505562d7bdc6d2ab91b637a916cdecdec911 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -313,6 +313,76 @@ public final class CraftServer implements Server { - private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher(); // Paper - private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer; // Paper - Custom Potion Mixes - -+ // Paper start - Folia region threading API -+ private final io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler(); -+ private final io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler asyncScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler(); -+ private final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler globalRegionScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler(); -+ -+ @Override -+ public final io.papermc.paper.threadedregions.scheduler.RegionScheduler getRegionScheduler() { -+ return this.regionizedScheduler; -+ } -+ -+ @Override -+ public final io.papermc.paper.threadedregions.scheduler.AsyncScheduler getAsyncScheduler() { -+ return this.asyncScheduler; -+ } -+ -+ @Override -+ public final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler getGlobalRegionScheduler() { -+ return this.globalRegionScheduler; -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(World world, io.papermc.paper.math.Position position) { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( -+ ((CraftWorld) world).getHandle(), position.blockX() >> 4, position.blockZ() >> 4 -+ ); -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(World world, io.papermc.paper.math.Position position, int squareRadiusChunks) { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( -+ ((CraftWorld) world).getHandle(), position.blockX() >> 4, position.blockZ() >> 4, squareRadiusChunks -+ ); -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(Location location) { -+ World world = location.getWorld(); -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( -+ ((CraftWorld) world).getHandle(), location.getBlockX() >> 4, location.getBlockZ() >> 4 -+ ); -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(Location location, int squareRadiusChunks) { -+ World world = location.getWorld(); -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( -+ ((CraftWorld) world).getHandle(), location.getBlockX() >> 4, location.getBlockZ() >> 4, squareRadiusChunks -+ ); -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(World world, int chunkX, int chunkZ) { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( -+ ((CraftWorld) world).getHandle(), chunkX, chunkZ -+ ); -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(World world, int chunkX, int chunkZ, int squareRadiusChunks) { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( -+ ((CraftWorld) world).getHandle(), chunkX, chunkZ, squareRadiusChunks -+ ); -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(Entity entity) { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandleRaw()); -+ } -+ // Paper end - Folia reagion threading API -+ - static { - ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); - ConfigurationSerialization.registerClass(CraftPlayerProfile.class); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 4209434ff066670000dadb0c59fea297f03300f4..df199c1cffa7795126ab83af67e184238ddb211d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -71,6 +71,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - private EntityDamageEvent lastDamageEvent; - private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY); - protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers -+ // Paper start - Folia shedulers -+ public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this); -+ private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this); -+ -+ @Override -+ public final io.papermc.paper.threadedregions.scheduler.EntityScheduler getScheduler() { -+ return this.apiScheduler; -+ }; -+ // Paper end - Folia schedulers - - public CraftEntity(final CraftServer server, final Entity entity) { - this.server = server; -@@ -487,6 +496,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return this.entity; - } - -+ // Paper start -+ public Entity getHandleRaw() { -+ return this.entity; -+ } -+ // Paper end -+ - @Override - public final EntityType getType() { - return this.entityType; diff --git a/patches/server/0836-Only-erase-allay-memory-on-non-item-targets.patch b/patches/server/0836-Only-erase-allay-memory-on-non-item-targets.patch new file mode 100644 index 0000000000..b26cfd040b --- /dev/null +++ b/patches/server/0836-Only-erase-allay-memory-on-non-item-targets.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bjarne Koll +Date: Fri, 4 Aug 2023 15:53:36 +0200 +Subject: [PATCH] Only erase allay memory on non-item targets + +Spigot incorrectly instanceOf checks the EntityTargetEvent#getTarget +against the internal ItemEntity type and removes the nearest wanted item +memory if said instanceOf check fails, (which is always the case) +causing allays to behave differently as they constantly loose their +target item. + +This commit fixes the faulty behaviour by instance performing a check +against the CraftItem type. + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java +index 07db92870f9efd515751453569f0dd7b6fada8fc..7d814e5b4b634674995d55ab97155f949f14ef3b 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java +@@ -35,8 +35,9 @@ public class GoToWantedItem { + if (event.isCancelled()) { + return false; + } +- if (!(event.getTarget() instanceof ItemEntity)) { ++ if (!(event.getTarget() instanceof org.bukkit.craftbukkit.entity.CraftItem)) { // Paper - only erase allay memory on non-item targets + memoryaccessor2.erase(); ++ return false; // Paper - only erase allay memory on non-item targets + } + + entityitem = (ItemEntity) ((org.bukkit.craftbukkit.entity.CraftEntity) event.getTarget()).getHandle(); diff --git a/patches/server/0837-Fix-rotation-when-spawning-display-entities.patch b/patches/server/0837-Fix-rotation-when-spawning-display-entities.patch new file mode 100644 index 0000000000..240a093118 --- /dev/null +++ b/patches/server/0837-Fix-rotation-when-spawning-display-entities.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gameoholic +Date: Sun, 30 Jul 2023 13:30:34 +0300 +Subject: [PATCH] Fix rotation when spawning display entities + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +index 8715d8e790b6735610e2f880f8c1f88a89967f21..6cf57640b3bd2bb0417129256ed77d9d67fcf04a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -254,6 +254,7 @@ public final class CraftEntityTypes { + Vector direction = spawnData.location().getDirection(); + entity.assignDirectionalMovement(new Vec3(direction.getX(), direction.getY(), direction.getZ()), 1.0); + }; ++ private static final BiConsumer ROT = (spawnData, entity) -> entity.setRot(spawnData.yaw(), spawnData.pitch()); // Paper + private static final Map, EntityTypeData> CLASS_TYPE_DATA = new HashMap<>(); + private static final Map> ENTITY_TYPE_DATA = new HashMap<>(); + +@@ -415,10 +416,10 @@ public final class CraftEntityTypes { + + // Set pos + register(new EntityTypeData<>(EntityType.MARKER, Marker.class, CraftMarker::new, createAndSetPos(net.minecraft.world.entity.EntityType.MARKER))); +- register(new EntityTypeData<>(EntityType.BLOCK_DISPLAY, BlockDisplay.class, CraftBlockDisplay::new, createAndSetPos(net.minecraft.world.entity.EntityType.BLOCK_DISPLAY))); ++ register(new EntityTypeData<>(EntityType.BLOCK_DISPLAY, BlockDisplay.class, CraftBlockDisplay::new, combine(createAndSetPos(net.minecraft.world.entity.EntityType.BLOCK_DISPLAY), ROT))); // Paper + register(new EntityTypeData<>(EntityType.INTERACTION, Interaction.class, CraftInteraction::new, createAndSetPos(net.minecraft.world.entity.EntityType.INTERACTION))); +- register(new EntityTypeData<>(EntityType.ITEM_DISPLAY, ItemDisplay.class, CraftItemDisplay::new, createAndSetPos(net.minecraft.world.entity.EntityType.ITEM_DISPLAY))); +- register(new EntityTypeData<>(EntityType.TEXT_DISPLAY, TextDisplay.class, CraftTextDisplay::new, createAndSetPos(net.minecraft.world.entity.EntityType.TEXT_DISPLAY))); ++ register(new EntityTypeData<>(EntityType.ITEM_DISPLAY, ItemDisplay.class, CraftItemDisplay::new, combine(createAndSetPos(net.minecraft.world.entity.EntityType.ITEM_DISPLAY), ROT))); // Paper ++ register(new EntityTypeData<>(EntityType.TEXT_DISPLAY, TextDisplay.class, CraftTextDisplay::new, combine(createAndSetPos(net.minecraft.world.entity.EntityType.TEXT_DISPLAY), ROT))); // Paper + + // MISC + register(new EntityTypeData<>(EntityType.ITEM, Item.class, CraftItem::new, spawnData -> { diff --git a/patches/server/0837-Only-erase-allay-memory-on-non-item-targets.patch b/patches/server/0837-Only-erase-allay-memory-on-non-item-targets.patch deleted file mode 100644 index b26cfd040b..0000000000 --- a/patches/server/0837-Only-erase-allay-memory-on-non-item-targets.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bjarne Koll -Date: Fri, 4 Aug 2023 15:53:36 +0200 -Subject: [PATCH] Only erase allay memory on non-item targets - -Spigot incorrectly instanceOf checks the EntityTargetEvent#getTarget -against the internal ItemEntity type and removes the nearest wanted item -memory if said instanceOf check fails, (which is always the case) -causing allays to behave differently as they constantly loose their -target item. - -This commit fixes the faulty behaviour by instance performing a check -against the CraftItem type. - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java -index 07db92870f9efd515751453569f0dd7b6fada8fc..7d814e5b4b634674995d55ab97155f949f14ef3b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java -@@ -35,8 +35,9 @@ public class GoToWantedItem { - if (event.isCancelled()) { - return false; - } -- if (!(event.getTarget() instanceof ItemEntity)) { -+ if (!(event.getTarget() instanceof org.bukkit.craftbukkit.entity.CraftItem)) { // Paper - only erase allay memory on non-item targets - memoryaccessor2.erase(); -+ return false; // Paper - only erase allay memory on non-item targets - } - - entityitem = (ItemEntity) ((org.bukkit.craftbukkit.entity.CraftEntity) event.getTarget()).getHandle(); diff --git a/patches/server/0838-Fix-rotation-when-spawning-display-entities.patch b/patches/server/0838-Fix-rotation-when-spawning-display-entities.patch deleted file mode 100644 index 240a093118..0000000000 --- a/patches/server/0838-Fix-rotation-when-spawning-display-entities.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Gameoholic -Date: Sun, 30 Jul 2023 13:30:34 +0300 -Subject: [PATCH] Fix rotation when spawning display entities - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -index 8715d8e790b6735610e2f880f8c1f88a89967f21..6cf57640b3bd2bb0417129256ed77d9d67fcf04a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -254,6 +254,7 @@ public final class CraftEntityTypes { - Vector direction = spawnData.location().getDirection(); - entity.assignDirectionalMovement(new Vec3(direction.getX(), direction.getY(), direction.getZ()), 1.0); - }; -+ private static final BiConsumer ROT = (spawnData, entity) -> entity.setRot(spawnData.yaw(), spawnData.pitch()); // Paper - private static final Map, EntityTypeData> CLASS_TYPE_DATA = new HashMap<>(); - private static final Map> ENTITY_TYPE_DATA = new HashMap<>(); - -@@ -415,10 +416,10 @@ public final class CraftEntityTypes { - - // Set pos - register(new EntityTypeData<>(EntityType.MARKER, Marker.class, CraftMarker::new, createAndSetPos(net.minecraft.world.entity.EntityType.MARKER))); -- register(new EntityTypeData<>(EntityType.BLOCK_DISPLAY, BlockDisplay.class, CraftBlockDisplay::new, createAndSetPos(net.minecraft.world.entity.EntityType.BLOCK_DISPLAY))); -+ register(new EntityTypeData<>(EntityType.BLOCK_DISPLAY, BlockDisplay.class, CraftBlockDisplay::new, combine(createAndSetPos(net.minecraft.world.entity.EntityType.BLOCK_DISPLAY), ROT))); // Paper - register(new EntityTypeData<>(EntityType.INTERACTION, Interaction.class, CraftInteraction::new, createAndSetPos(net.minecraft.world.entity.EntityType.INTERACTION))); -- register(new EntityTypeData<>(EntityType.ITEM_DISPLAY, ItemDisplay.class, CraftItemDisplay::new, createAndSetPos(net.minecraft.world.entity.EntityType.ITEM_DISPLAY))); -- register(new EntityTypeData<>(EntityType.TEXT_DISPLAY, TextDisplay.class, CraftTextDisplay::new, createAndSetPos(net.minecraft.world.entity.EntityType.TEXT_DISPLAY))); -+ register(new EntityTypeData<>(EntityType.ITEM_DISPLAY, ItemDisplay.class, CraftItemDisplay::new, combine(createAndSetPos(net.minecraft.world.entity.EntityType.ITEM_DISPLAY), ROT))); // Paper -+ register(new EntityTypeData<>(EntityType.TEXT_DISPLAY, TextDisplay.class, CraftTextDisplay::new, combine(createAndSetPos(net.minecraft.world.entity.EntityType.TEXT_DISPLAY), ROT))); // Paper - - // MISC - register(new EntityTypeData<>(EntityType.ITEM, Item.class, CraftItem::new, spawnData -> { diff --git a/patches/server/0838-Only-capture-actual-tree-growth.patch b/patches/server/0838-Only-capture-actual-tree-growth.patch new file mode 100644 index 0000000000..f1dee3ad48 --- /dev/null +++ b/patches/server/0838-Only-capture-actual-tree-growth.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 21 Aug 2021 18:53:03 -0700 +Subject: [PATCH] Only capture actual tree growth + + +diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +index f8f570a97789ab16e57774f233506a289277d5d9..18304349c9ab24657c4152aff800dba969174665 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -550,6 +550,7 @@ public interface DispenseItemBehavior { + if (!fertilizeEvent.isCancelled()) { + for (org.bukkit.block.BlockState blockstate : blocks) { + blockstate.update(true); ++ worldserver.checkCapturedTreeStateForObserverNotify(blockposition, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed + } + } + } +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index e9096a138175448279a03a55043982b6d83fbe12..0db41d36d5daf015c750fb0246ab3e5da1cd81a2 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2198,6 +2198,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + return range <= 0 ? 64.0 * 64.0 : range * range; // 64 is taken from default in ServerLevel#levelEvent + } + // Paper end - respect global sound events gamerule ++ // Paper start - notify observers even if grow failed ++ public void checkCapturedTreeStateForObserverNotify(final BlockPos pos, final org.bukkit.craftbukkit.block.CraftBlockState craftBlockState) { ++ // notify observers if the block state is the same and the Y level equals the original y level (for mega trees) ++ // blocks at the same Y level with the same state can be assumed to be saplings which trigger observers regardless of if the ++ // tree grew or not ++ if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) { ++ this.notifyAndUpdatePhysics(craftBlockState.getPosition(), null, craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getFlag(), 512); ++ } ++ } ++ // Paper end - notify observers even if grow failed + + @Override + public CrashReportCategory fillReportDetails(CrashReport report) { +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index f81b3e050f21ce10ea86892d9a6bee9a42561514..cb6bcf8b61793882252827309ffa99526244e445 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -469,6 +469,7 @@ public final class ItemStack implements DataComponentHolder { + for (CraftBlockState blockstate : blocks) { + // SPIGOT-7572 - Move fix for SPIGOT-7248 to CapturedBlockState, to allow bees in bee nest + CapturedBlockState.setBlockState(blockstate); ++ world.checkCapturedTreeStateForObserverNotify(blockposition, blockstate); // Paper - notify observers even if grow failed + } + entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat + } +diff --git a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java +index 2d7290ace5fc8890325a8ec623075ad32f9b1d44..d262a5a6da57ef9ba9a6fe0dfbc88f577105e74f 100644 +--- a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java +@@ -86,6 +86,7 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { + if (event == null || !event.isCancelled()) { + for (BlockState blockstate : blocks) { + CapturedBlockState.setBlockState(blockstate); ++ world.checkCapturedTreeStateForObserverNotify(pos, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed + } + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 7afb933782cac7e1ad621e80211c13066c680ad7..6dceb6082538df6f6147254e861d1cec8af7ec50 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -572,6 +572,7 @@ public class CraftBlock implements Block { + if (!event.isCancelled()) { + for (BlockState blockstate : blocks) { + blockstate.update(true); ++ world.checkCapturedTreeStateForObserverNotify(this.position, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed + } + } + } diff --git a/patches/server/0839-Only-capture-actual-tree-growth.patch b/patches/server/0839-Only-capture-actual-tree-growth.patch deleted file mode 100644 index 58fb59ab7d..0000000000 --- a/patches/server/0839-Only-capture-actual-tree-growth.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 21 Aug 2021 18:53:03 -0700 -Subject: [PATCH] Only capture actual tree growth - - -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index f8f570a97789ab16e57774f233506a289277d5d9..18304349c9ab24657c4152aff800dba969174665 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -550,6 +550,7 @@ public interface DispenseItemBehavior { - if (!fertilizeEvent.isCancelled()) { - for (org.bukkit.block.BlockState blockstate : blocks) { - blockstate.update(true); -+ worldserver.checkCapturedTreeStateForObserverNotify(blockposition, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed - } - } - } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 537a755d097d7713404d83dc47cd17828b15a906..9270584d74edf5c1af473b1a13f7edca74cc1ec7 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2228,6 +2228,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - return range <= 0 ? 64.0 * 64.0 : range * range; // 64 is taken from default in ServerLevel#levelEvent - } - // Paper end - respect global sound events gamerule -+ // Paper start - notify observers even if grow failed -+ public void checkCapturedTreeStateForObserverNotify(final BlockPos pos, final org.bukkit.craftbukkit.block.CraftBlockState craftBlockState) { -+ // notify observers if the block state is the same and the Y level equals the original y level (for mega trees) -+ // blocks at the same Y level with the same state can be assumed to be saplings which trigger observers regardless of if the -+ // tree grew or not -+ if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) { -+ this.notifyAndUpdatePhysics(craftBlockState.getPosition(), null, craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getFlag(), 512); -+ } -+ } -+ // Paper end - notify observers even if grow failed - - @Override - public CrashReportCategory fillReportDetails(CrashReport report) { -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index f81b3e050f21ce10ea86892d9a6bee9a42561514..cb6bcf8b61793882252827309ffa99526244e445 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -469,6 +469,7 @@ public final class ItemStack implements DataComponentHolder { - for (CraftBlockState blockstate : blocks) { - // SPIGOT-7572 - Move fix for SPIGOT-7248 to CapturedBlockState, to allow bees in bee nest - CapturedBlockState.setBlockState(blockstate); -+ world.checkCapturedTreeStateForObserverNotify(blockposition, blockstate); // Paper - notify observers even if grow failed - } - entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat - } -diff --git a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java -index 2d7290ace5fc8890325a8ec623075ad32f9b1d44..d262a5a6da57ef9ba9a6fe0dfbc88f577105e74f 100644 ---- a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java -@@ -86,6 +86,7 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { - if (event == null || !event.isCancelled()) { - for (BlockState blockstate : blocks) { - CapturedBlockState.setBlockState(blockstate); -+ world.checkCapturedTreeStateForObserverNotify(pos, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed - } - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 7afb933782cac7e1ad621e80211c13066c680ad7..6dceb6082538df6f6147254e861d1cec8af7ec50 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -572,6 +572,7 @@ public class CraftBlock implements Block { - if (!event.isCancelled()) { - for (BlockState blockstate : blocks) { - blockstate.update(true); -+ world.checkCapturedTreeStateForObserverNotify(this.position, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed - } - } - } diff --git a/patches/server/0839-Use-correct-source-for-mushroom-block-spread-event.patch b/patches/server/0839-Use-correct-source-for-mushroom-block-spread-event.patch new file mode 100644 index 0000000000..658d9ec376 --- /dev/null +++ b/patches/server/0839-Use-correct-source-for-mushroom-block-spread-event.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Tue, 8 Aug 2023 11:49:32 +0200 +Subject: [PATCH] Use correct source for mushroom block spread event + + +diff --git a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java +index 61fb134686c7cd538ae2f8fefe78fd9618a9990b..7900856c9e86afe907c00c9ac31bec93ece50abe 100644 +--- a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java +@@ -68,6 +68,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock { + } + + BlockPos blockposition2 = pos.offset(random.nextInt(3) - 1, random.nextInt(2) - random.nextInt(2), random.nextInt(3) - 1); ++ final BlockPos sourcePos = pos; // Paper - Use correct source for mushroom block spread event + + for (int j = 0; j < 4; ++j) { + if (world.isEmptyBlock(blockposition2) && state.canSurvive(world, blockposition2)) { +@@ -78,7 +79,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock { + } + + if (world.isEmptyBlock(blockposition2) && state.canSurvive(world, blockposition2)) { +- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition2, state, 2); // CraftBukkit ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, sourcePos, blockposition2, state, 2); // CraftBukkit // Paper - Use correct source for mushroom block spread event + } + } + diff --git a/patches/server/0840-Respect-randomizeData-on-more-entities-when-spawning.patch b/patches/server/0840-Respect-randomizeData-on-more-entities-when-spawning.patch new file mode 100644 index 0000000000..67a5238077 --- /dev/null +++ b/patches/server/0840-Respect-randomizeData-on-more-entities-when-spawning.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 13 Jul 2023 16:10:07 -0700 +Subject: [PATCH] Respect randomizeData on more entities when spawning + +* ItemEntity +* PrimedTNT +* FireworkRocketEntity +* ExperienceOrb + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +index 6cf57640b3bd2bb0417129256ed77d9d67fcf04a..3b5277f90b5bba30d40d79ba67903a8d04d2c0df 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -255,6 +255,13 @@ public final class CraftEntityTypes { + entity.assignDirectionalMovement(new Vec3(direction.getX(), direction.getY(), direction.getZ()), 1.0); + }; + private static final BiConsumer ROT = (spawnData, entity) -> entity.setRot(spawnData.yaw(), spawnData.pitch()); // Paper ++ // Paper start - respect randomizeData ++ private static final BiConsumer CLEAR_MOVE_IF_NOT_RANDOMIZED = (spawnData, entity) -> { ++ if (!spawnData.randomizeData()) { ++ entity.setDeltaMovement(net.minecraft.world.phys.Vec3.ZERO); ++ } ++ }; ++ // Paper end - respect randomizeData + private static final Map, EntityTypeData> CLASS_TYPE_DATA = new HashMap<>(); + private static final Map> ENTITY_TYPE_DATA = new HashMap<>(); + +@@ -428,11 +435,12 @@ public final class CraftEntityTypes { + net.minecraft.world.item.ItemStack itemStack = new net.minecraft.world.item.ItemStack(Items.STONE); + ItemEntity item = new ItemEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), itemStack); + item.setPickUpDelay(10); ++ CLEAR_MOVE_IF_NOT_RANDOMIZED.accept(spawnData, item); // Paper - respect randomizeData + + return item; + })); + register(new EntityTypeData<>(EntityType.EXPERIENCE_ORB, ExperienceOrb.class, CraftExperienceOrb::new, +- spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null) // Paper ++ combine(combine(spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null), CLEAR_MOVE_IF_NOT_RANDOMIZED), (spawnData, experienceOrb) -> { if (!spawnData.randomizeData()) { experienceOrb.setYRot(0); } }) // Paper - respect randomizeData + )); + register(new EntityTypeData<>(EntityType.AREA_EFFECT_CLOUD, AreaEffectCloud.class, CraftAreaEffectCloud::new, createAndMove(net.minecraft.world.entity.EntityType.AREA_EFFECT_CLOUD))); // Paper - set area effect cloud rotation + register(new EntityTypeData<>(EntityType.EGG, Egg.class, CraftEgg::new, spawnData -> new ThrownEgg(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.EGG)))); +@@ -443,12 +451,23 @@ public final class CraftEntityTypes { + net.minecraft.world.entity.projectile.ThrownPotion entity = new net.minecraft.world.entity.projectile.ThrownPotion(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.SPLASH_POTION)); + return entity; + })); +- register(new EntityTypeData<>(EntityType.TNT, TNTPrimed.class, CraftTNTPrimed::new, spawnData -> new PrimedTnt(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null))); ++ register(new EntityTypeData<>(EntityType.TNT, TNTPrimed.class, CraftTNTPrimed::new, combine(spawnData -> new PrimedTnt(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null), CLEAR_MOVE_IF_NOT_RANDOMIZED))); // Paper - respect randomizeData + register(new EntityTypeData<>(EntityType.FALLING_BLOCK, FallingBlock.class, CraftFallingBlock::new, spawnData -> { + BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z()); + return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly + })); +- register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), FireworkRocketEntity.getDefaultItem()))); // Paper - pass correct default to rocket for data storage ++ // Paper start - respect randomizeData ++ register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> { ++ FireworkRocketEntity entity = new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), FireworkRocketEntity.getDefaultItem()); // Paper - pass correct default to rocket for data storage ++ if (!spawnData.randomizeData()) { ++ // logic below was taken from FireworkRocketEntity constructor ++ entity.setDeltaMovement(0, 0.05, 0); ++ //noinspection PointlessArithmeticExpression ++ entity.lifetime = 10 * 1 + 6; ++ } ++ return entity; ++ })); ++ // Paper end - respect randomizeData + register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null))); + register(new EntityTypeData<>(EntityType.COMMAND_BLOCK_MINECART, CommandMinecart.class, CraftMinecartCommand::new, createMinecart(net.minecraft.world.entity.EntityType.COMMAND_BLOCK_MINECART))); + register(new EntityTypeData<>(EntityType.MINECART, RideableMinecart.class, CraftMinecartRideable::new, createMinecart(net.minecraft.world.entity.EntityType.MINECART))); diff --git a/patches/server/0840-Use-correct-source-for-mushroom-block-spread-event.patch b/patches/server/0840-Use-correct-source-for-mushroom-block-spread-event.patch deleted file mode 100644 index 658d9ec376..0000000000 --- a/patches/server/0840-Use-correct-source-for-mushroom-block-spread-event.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Tue, 8 Aug 2023 11:49:32 +0200 -Subject: [PATCH] Use correct source for mushroom block spread event - - -diff --git a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java -index 61fb134686c7cd538ae2f8fefe78fd9618a9990b..7900856c9e86afe907c00c9ac31bec93ece50abe 100644 ---- a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java -@@ -68,6 +68,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock { - } - - BlockPos blockposition2 = pos.offset(random.nextInt(3) - 1, random.nextInt(2) - random.nextInt(2), random.nextInt(3) - 1); -+ final BlockPos sourcePos = pos; // Paper - Use correct source for mushroom block spread event - - for (int j = 0; j < 4; ++j) { - if (world.isEmptyBlock(blockposition2) && state.canSurvive(world, blockposition2)) { -@@ -78,7 +79,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock { - } - - if (world.isEmptyBlock(blockposition2) && state.canSurvive(world, blockposition2)) { -- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition2, state, 2); // CraftBukkit -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, sourcePos, blockposition2, state, 2); // CraftBukkit // Paper - Use correct source for mushroom block spread event - } - } - diff --git a/patches/server/0841-Respect-randomizeData-on-more-entities-when-spawning.patch b/patches/server/0841-Respect-randomizeData-on-more-entities-when-spawning.patch deleted file mode 100644 index 67a5238077..0000000000 --- a/patches/server/0841-Respect-randomizeData-on-more-entities-when-spawning.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 13 Jul 2023 16:10:07 -0700 -Subject: [PATCH] Respect randomizeData on more entities when spawning - -* ItemEntity -* PrimedTNT -* FireworkRocketEntity -* ExperienceOrb - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -index 6cf57640b3bd2bb0417129256ed77d9d67fcf04a..3b5277f90b5bba30d40d79ba67903a8d04d2c0df 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -255,6 +255,13 @@ public final class CraftEntityTypes { - entity.assignDirectionalMovement(new Vec3(direction.getX(), direction.getY(), direction.getZ()), 1.0); - }; - private static final BiConsumer ROT = (spawnData, entity) -> entity.setRot(spawnData.yaw(), spawnData.pitch()); // Paper -+ // Paper start - respect randomizeData -+ private static final BiConsumer CLEAR_MOVE_IF_NOT_RANDOMIZED = (spawnData, entity) -> { -+ if (!spawnData.randomizeData()) { -+ entity.setDeltaMovement(net.minecraft.world.phys.Vec3.ZERO); -+ } -+ }; -+ // Paper end - respect randomizeData - private static final Map, EntityTypeData> CLASS_TYPE_DATA = new HashMap<>(); - private static final Map> ENTITY_TYPE_DATA = new HashMap<>(); - -@@ -428,11 +435,12 @@ public final class CraftEntityTypes { - net.minecraft.world.item.ItemStack itemStack = new net.minecraft.world.item.ItemStack(Items.STONE); - ItemEntity item = new ItemEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), itemStack); - item.setPickUpDelay(10); -+ CLEAR_MOVE_IF_NOT_RANDOMIZED.accept(spawnData, item); // Paper - respect randomizeData - - return item; - })); - register(new EntityTypeData<>(EntityType.EXPERIENCE_ORB, ExperienceOrb.class, CraftExperienceOrb::new, -- spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null) // Paper -+ combine(combine(spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null), CLEAR_MOVE_IF_NOT_RANDOMIZED), (spawnData, experienceOrb) -> { if (!spawnData.randomizeData()) { experienceOrb.setYRot(0); } }) // Paper - respect randomizeData - )); - register(new EntityTypeData<>(EntityType.AREA_EFFECT_CLOUD, AreaEffectCloud.class, CraftAreaEffectCloud::new, createAndMove(net.minecraft.world.entity.EntityType.AREA_EFFECT_CLOUD))); // Paper - set area effect cloud rotation - register(new EntityTypeData<>(EntityType.EGG, Egg.class, CraftEgg::new, spawnData -> new ThrownEgg(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.EGG)))); -@@ -443,12 +451,23 @@ public final class CraftEntityTypes { - net.minecraft.world.entity.projectile.ThrownPotion entity = new net.minecraft.world.entity.projectile.ThrownPotion(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.SPLASH_POTION)); - return entity; - })); -- register(new EntityTypeData<>(EntityType.TNT, TNTPrimed.class, CraftTNTPrimed::new, spawnData -> new PrimedTnt(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null))); -+ register(new EntityTypeData<>(EntityType.TNT, TNTPrimed.class, CraftTNTPrimed::new, combine(spawnData -> new PrimedTnt(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null), CLEAR_MOVE_IF_NOT_RANDOMIZED))); // Paper - respect randomizeData - register(new EntityTypeData<>(EntityType.FALLING_BLOCK, FallingBlock.class, CraftFallingBlock::new, spawnData -> { - BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z()); - return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly - })); -- register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), FireworkRocketEntity.getDefaultItem()))); // Paper - pass correct default to rocket for data storage -+ // Paper start - respect randomizeData -+ register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> { -+ FireworkRocketEntity entity = new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), FireworkRocketEntity.getDefaultItem()); // Paper - pass correct default to rocket for data storage -+ if (!spawnData.randomizeData()) { -+ // logic below was taken from FireworkRocketEntity constructor -+ entity.setDeltaMovement(0, 0.05, 0); -+ //noinspection PointlessArithmeticExpression -+ entity.lifetime = 10 * 1 + 6; -+ } -+ return entity; -+ })); -+ // Paper end - respect randomizeData - register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null))); - register(new EntityTypeData<>(EntityType.COMMAND_BLOCK_MINECART, CommandMinecart.class, CraftMinecartCommand::new, createMinecart(net.minecraft.world.entity.EntityType.COMMAND_BLOCK_MINECART))); - register(new EntityTypeData<>(EntityType.MINECART, RideableMinecart.class, CraftMinecartRideable::new, createMinecart(net.minecraft.world.entity.EntityType.MINECART))); diff --git a/patches/server/0841-Use-correct-seed-on-api-world-load.patch b/patches/server/0841-Use-correct-seed-on-api-world-load.patch new file mode 100644 index 0000000000..997631e23b --- /dev/null +++ b/patches/server/0841-Use-correct-seed-on-api-world-load.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Florian Schmidt +Date: Fri, 28 Jul 2023 14:14:35 +0200 +Subject: [PATCH] Use correct seed on api world load + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 46807d5d94a0f90b230dfaf4d37378a3bfa21414..da3819f49b105bd98ce94b5abdf1c7652ff625a4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1388,7 +1388,7 @@ public final class CraftServer implements Server { + net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, iregistrycustom_dimension, this.console.options.has("recreateRegionFiles")); + } + +- long j = BiomeManager.obfuscateSeed(creator.seed()); ++ long j = BiomeManager.obfuscateSeed(worlddata.worldGenOptions().seed()); // Paper - use world seed + List list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata)); + LevelStem worlddimension = iregistry.getValue(actualDimension); + diff --git a/patches/server/0842-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch b/patches/server/0842-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch new file mode 100644 index 0000000000..d87f310ded --- /dev/null +++ b/patches/server/0842-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Wed, 9 Aug 2023 14:00:40 -0700 +Subject: [PATCH] Remove UpgradeData neighbour ticks outside of range + +The lists are only supposed to contain ticks for the 1 radius +neighbours of the chunk. + +diff --git a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java +index 5c7c8fb3c67047ddc1b92f03e889839b5a303ff4..ce3d79ebc7f933d0b34b3f8f71bbec872076847a 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java ++++ b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java +@@ -113,6 +113,25 @@ public class UpgradeData { + } + } + ++ // Paper start - filter out relocated neighbour ticks ++ // The lists are only supposed to contain ticks for the 1 radius neighbours of the chunk ++ private static void filterTickList(int chunkX, int chunkZ, List> ticks) { ++ for (java.util.Iterator> iterator = ticks.iterator(); iterator.hasNext();) { ++ SavedTick tick = iterator.next(); ++ BlockPos tickPos = tick.pos(); ++ int tickCX = tickPos.getX() >> 4; ++ int tickCZ = tickPos.getZ() >> 4; ++ ++ int dist = Math.max(Math.abs(chunkX - tickCX), Math.abs(chunkZ - tickCZ)); ++ ++ if (dist != 1) { ++ LOGGER.warn("Neighbour tick '" + tick + "' serialized in chunk (" + chunkX + "," + chunkZ + ") is too far (" + tickCX + "," + tickCZ + ")"); ++ iterator.remove(); ++ } ++ } ++ } ++ // Paper end - filter out relocated neighbour ticks ++ + public void upgrade(LevelChunk chunk) { + this.upgradeInside(chunk); + +@@ -120,6 +139,11 @@ public class UpgradeData { + upgradeSides(chunk, direction8); + } + ++ // Paper start - filter out relocated neighbour ticks ++ filterTickList(chunk.locX, chunk.locZ, this.neighborBlockTicks); ++ filterTickList(chunk.locX, chunk.locZ, this.neighborFluidTicks); ++ // Paper end - filter out relocated neighbour ticks ++ + Level level = chunk.getLevel(); + this.neighborBlockTicks.forEach(tick -> { + Block block = tick.type() == Blocks.AIR ? level.getBlockState(tick.pos()).getBlock() : tick.type(); diff --git a/patches/server/0842-Use-correct-seed-on-api-world-load.patch b/patches/server/0842-Use-correct-seed-on-api-world-load.patch deleted file mode 100644 index 099c091a64..0000000000 --- a/patches/server/0842-Use-correct-seed-on-api-world-load.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Florian Schmidt -Date: Fri, 28 Jul 2023 14:14:35 +0200 -Subject: [PATCH] Use correct seed on api world load - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 0193505562d7bdc6d2ab91b637a916cdecdec911..3cf3b353cfb4337abdbb3b6842fd8fa128271948 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1389,7 +1389,7 @@ public final class CraftServer implements Server { - net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, iregistrycustom_dimension, this.console.options.has("recreateRegionFiles")); - } - -- long j = BiomeManager.obfuscateSeed(creator.seed()); -+ long j = BiomeManager.obfuscateSeed(worlddata.worldGenOptions().seed()); // Paper - use world seed - List list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata)); - LevelStem worlddimension = iregistry.getValue(actualDimension); - diff --git a/patches/server/0843-Cache-map-ids-on-item-frames.patch b/patches/server/0843-Cache-map-ids-on-item-frames.patch new file mode 100644 index 0000000000..38554e1a9c --- /dev/null +++ b/patches/server/0843-Cache-map-ids-on-item-frames.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Mon, 7 Aug 2023 12:58:28 +0200 +Subject: [PATCH] Cache map ids on item frames + + +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 3cdcc4f44608d24550f2a8c6f3f5ce675d7777c5..7118e1f806af98159ec292f9340d7e4004e2b486 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -121,7 +121,7 @@ public class ServerEntity { + ItemStack itemstack = entityitemframe.getItem(); + + if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable +- MapId mapid = (MapId) itemstack.get(DataComponents.MAP_ID); ++ MapId mapid = entityitemframe.cachedMapId; // Paper - Perf: Cache map ids on item frames + MapItemSavedData worldmap = MapItem.getSavedData(mapid, this.level); + + if (worldmap != null) { +diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java +index 65f7f1f98f415a564aadb440d3a67143699e43db..d6f835320014c07f9d174d05929ed8cc16a10c10 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java +@@ -51,6 +51,7 @@ public class ItemFrame extends HangingEntity { + private static final float HEIGHT = 0.75F; + public float dropChance; + public boolean fixed; ++ public @Nullable MapId cachedMapId; // Paper - Perf: Cache map ids on item frames + + public ItemFrame(EntityType type, Level world) { + super(type, world); +@@ -334,6 +335,7 @@ public class ItemFrame extends HangingEntity { + } + + private void onItemChanged(ItemStack stack) { ++ this.cachedMapId = stack.getComponents().get(net.minecraft.core.component.DataComponents.MAP_ID); // Paper - Perf: Cache map ids on item frames + if (!stack.isEmpty() && stack.getFrame() != this) { + stack.setEntityRepresentation(this); + } diff --git a/patches/server/0843-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch b/patches/server/0843-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch deleted file mode 100644 index d87f310ded..0000000000 --- a/patches/server/0843-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Wed, 9 Aug 2023 14:00:40 -0700 -Subject: [PATCH] Remove UpgradeData neighbour ticks outside of range - -The lists are only supposed to contain ticks for the 1 radius -neighbours of the chunk. - -diff --git a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -index 5c7c8fb3c67047ddc1b92f03e889839b5a303ff4..ce3d79ebc7f933d0b34b3f8f71bbec872076847a 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -+++ b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -@@ -113,6 +113,25 @@ public class UpgradeData { - } - } - -+ // Paper start - filter out relocated neighbour ticks -+ // The lists are only supposed to contain ticks for the 1 radius neighbours of the chunk -+ private static void filterTickList(int chunkX, int chunkZ, List> ticks) { -+ for (java.util.Iterator> iterator = ticks.iterator(); iterator.hasNext();) { -+ SavedTick tick = iterator.next(); -+ BlockPos tickPos = tick.pos(); -+ int tickCX = tickPos.getX() >> 4; -+ int tickCZ = tickPos.getZ() >> 4; -+ -+ int dist = Math.max(Math.abs(chunkX - tickCX), Math.abs(chunkZ - tickCZ)); -+ -+ if (dist != 1) { -+ LOGGER.warn("Neighbour tick '" + tick + "' serialized in chunk (" + chunkX + "," + chunkZ + ") is too far (" + tickCX + "," + tickCZ + ")"); -+ iterator.remove(); -+ } -+ } -+ } -+ // Paper end - filter out relocated neighbour ticks -+ - public void upgrade(LevelChunk chunk) { - this.upgradeInside(chunk); - -@@ -120,6 +139,11 @@ public class UpgradeData { - upgradeSides(chunk, direction8); - } - -+ // Paper start - filter out relocated neighbour ticks -+ filterTickList(chunk.locX, chunk.locZ, this.neighborBlockTicks); -+ filterTickList(chunk.locX, chunk.locZ, this.neighborFluidTicks); -+ // Paper end - filter out relocated neighbour ticks -+ - Level level = chunk.getLevel(); - this.neighborBlockTicks.forEach(tick -> { - Block block = tick.type() == Blocks.AIR ? level.getBlockState(tick.pos()).getBlock() : tick.type(); diff --git a/patches/server/0844-API-for-updating-recipes-on-clients.patch b/patches/server/0844-API-for-updating-recipes-on-clients.patch new file mode 100644 index 0000000000..28b0572357 --- /dev/null +++ b/patches/server/0844-API-for-updating-recipes-on-clients.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 21 Aug 2021 17:25:38 -0700 +Subject: [PATCH] API for updating recipes on clients + + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 74cbc6092d49f573f7fab1895c42a0360bb80bdf..db19a2483f37fb3554f86577e44162f6fe29592a 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1448,6 +1448,13 @@ public abstract class PlayerList { + } + + public void reloadResources() { ++ // Paper start - API for updating recipes on clients ++ this.reloadAdvancementData(); ++ this.reloadTagData(); ++ this.reloadRecipeData(); ++ } ++ public void reloadAdvancementData() { ++ // Paper end - API for updating recipes on clients + // CraftBukkit start + /*Iterator iterator = this.advancements.values().iterator(); + +@@ -1463,7 +1470,13 @@ public abstract class PlayerList { + } + // CraftBukkit end + ++ // Paper start - API for updating recipes on clients ++ } ++ public void reloadTagData() { + this.broadcastAll(new ClientboundUpdateTagsPacket(TagNetworkSerialization.serializeTagsToNetwork(this.registries))); ++ } ++ public void reloadRecipeData() { ++ // Paper end - API for updating recipes on clients + RecipeManager craftingmanager = this.server.getRecipeManager(); + ClientboundUpdateRecipesPacket packetplayoutrecipeupdate = new ClientboundUpdateRecipesPacket(craftingmanager.getSynchronizedItemProperties(), craftingmanager.getSynchronizedStonecutterRecipes()); + Iterator iterator1 = this.players.iterator(); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index da3819f49b105bd98ce94b5abdf1c7652ff625a4..fa505c0714bb95b2ab08b4bbb9ea79ce98898f4b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1178,6 +1178,18 @@ public final class CraftServer implements Server { + ReloadCommand.reload(this.console); + } + ++ // Paper start - API for updating recipes on clients ++ @Override ++ public void updateResources() { ++ this.playerList.reloadResources(); ++ } ++ ++ @Override ++ public void updateRecipes() { ++ this.playerList.reloadRecipeData(); ++ } ++ // Paper end - API for updating recipes on clients ++ + private void loadIcon() { + this.icon = new CraftIconCache(null); + try { +@@ -1557,6 +1569,13 @@ public final class CraftServer implements Server { + + @Override + public boolean addRecipe(Recipe recipe) { ++ // Paper start - API for updating recipes on clients ++ return this.addRecipe(recipe, false); ++ } ++ ++ @Override ++ public boolean addRecipe(Recipe recipe, boolean resendRecipes) { ++ // Paper end - API for updating recipes on clients + CraftRecipe toAdd; + if (recipe instanceof CraftRecipe) { + toAdd = (CraftRecipe) recipe; +@@ -1588,6 +1607,11 @@ public final class CraftServer implements Server { + } + } + toAdd.addToCraftingManager(); ++ // Paper start - API for updating recipes on clients ++ if (true || resendRecipes) { // Always needs to be resent now... TODO ++ this.playerList.reloadRecipeData(); ++ } ++ // Paper end - API for updating recipes on clients + return true; + } + +@@ -1768,9 +1792,23 @@ public final class CraftServer implements Server { + + @Override + public boolean removeRecipe(NamespacedKey recipeKey) { ++ // Paper start - API for updating recipes on clients ++ return this.removeRecipe(recipeKey, false); ++ } ++ ++ @Override ++ public boolean removeRecipe(NamespacedKey recipeKey, boolean resendRecipes) { ++ // Paper end - API for updating recipes on clients + Preconditions.checkArgument(recipeKey != null, "recipeKey == null"); + +- return this.getServer().getRecipeManager().removeRecipe(CraftRecipe.toMinecraft(recipeKey)); ++ // Paper start - resend recipes on successful removal ++ final ResourceKey> minecraftKey = CraftRecipe.toMinecraft(recipeKey); ++ final boolean removed = this.getServer().getRecipeManager().removeRecipe(minecraftKey); ++ if (removed/* && resendRecipes*/) { // TODO Always need to resend them rn - deprecate this method? ++ this.playerList.reloadRecipeData(); ++ } ++ return removed; ++ // Paper end - resend recipes on successful removal + } + + @Override diff --git a/patches/server/0844-Cache-map-ids-on-item-frames.patch b/patches/server/0844-Cache-map-ids-on-item-frames.patch deleted file mode 100644 index 38554e1a9c..0000000000 --- a/patches/server/0844-Cache-map-ids-on-item-frames.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Mon, 7 Aug 2023 12:58:28 +0200 -Subject: [PATCH] Cache map ids on item frames - - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 3cdcc4f44608d24550f2a8c6f3f5ce675d7777c5..7118e1f806af98159ec292f9340d7e4004e2b486 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -121,7 +121,7 @@ public class ServerEntity { - ItemStack itemstack = entityitemframe.getItem(); - - if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable -- MapId mapid = (MapId) itemstack.get(DataComponents.MAP_ID); -+ MapId mapid = entityitemframe.cachedMapId; // Paper - Perf: Cache map ids on item frames - MapItemSavedData worldmap = MapItem.getSavedData(mapid, this.level); - - if (worldmap != null) { -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -index 65f7f1f98f415a564aadb440d3a67143699e43db..d6f835320014c07f9d174d05929ed8cc16a10c10 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -@@ -51,6 +51,7 @@ public class ItemFrame extends HangingEntity { - private static final float HEIGHT = 0.75F; - public float dropChance; - public boolean fixed; -+ public @Nullable MapId cachedMapId; // Paper - Perf: Cache map ids on item frames - - public ItemFrame(EntityType type, Level world) { - super(type, world); -@@ -334,6 +335,7 @@ public class ItemFrame extends HangingEntity { - } - - private void onItemChanged(ItemStack stack) { -+ this.cachedMapId = stack.getComponents().get(net.minecraft.core.component.DataComponents.MAP_ID); // Paper - Perf: Cache map ids on item frames - if (!stack.isEmpty() && stack.getFrame() != this) { - stack.setEntityRepresentation(this); - } diff --git a/patches/server/0845-API-for-updating-recipes-on-clients.patch b/patches/server/0845-API-for-updating-recipes-on-clients.patch deleted file mode 100644 index 0435961d1f..0000000000 --- a/patches/server/0845-API-for-updating-recipes-on-clients.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 21 Aug 2021 17:25:38 -0700 -Subject: [PATCH] API for updating recipes on clients - - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index a9063533ea4b2b349d476127b99c822203d7dfcb..a1228d09b91dca3989a4be3120f9724a6e138040 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1450,6 +1450,13 @@ public abstract class PlayerList { - } - - public void reloadResources() { -+ // Paper start - API for updating recipes on clients -+ this.reloadAdvancementData(); -+ this.reloadTagData(); -+ this.reloadRecipeData(); -+ } -+ public void reloadAdvancementData() { -+ // Paper end - API for updating recipes on clients - // CraftBukkit start - /*Iterator iterator = this.advancements.values().iterator(); - -@@ -1465,7 +1472,13 @@ public abstract class PlayerList { - } - // CraftBukkit end - -+ // Paper start - API for updating recipes on clients -+ } -+ public void reloadTagData() { - this.broadcastAll(new ClientboundUpdateTagsPacket(TagNetworkSerialization.serializeTagsToNetwork(this.registries))); -+ } -+ public void reloadRecipeData() { -+ // Paper end - API for updating recipes on clients - RecipeManager craftingmanager = this.server.getRecipeManager(); - ClientboundUpdateRecipesPacket packetplayoutrecipeupdate = new ClientboundUpdateRecipesPacket(craftingmanager.getSynchronizedItemProperties(), craftingmanager.getSynchronizedStonecutterRecipes()); - Iterator iterator1 = this.players.iterator(); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 3cf3b353cfb4337abdbb3b6842fd8fa128271948..0433de3c2455cf18584d5ab651843f8d1d874036 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1179,6 +1179,18 @@ public final class CraftServer implements Server { - ReloadCommand.reload(this.console); - } - -+ // Paper start - API for updating recipes on clients -+ @Override -+ public void updateResources() { -+ this.playerList.reloadResources(); -+ } -+ -+ @Override -+ public void updateRecipes() { -+ this.playerList.reloadRecipeData(); -+ } -+ // Paper end - API for updating recipes on clients -+ - private void loadIcon() { - this.icon = new CraftIconCache(null); - try { -@@ -1558,6 +1570,13 @@ public final class CraftServer implements Server { - - @Override - public boolean addRecipe(Recipe recipe) { -+ // Paper start - API for updating recipes on clients -+ return this.addRecipe(recipe, false); -+ } -+ -+ @Override -+ public boolean addRecipe(Recipe recipe, boolean resendRecipes) { -+ // Paper end - API for updating recipes on clients - CraftRecipe toAdd; - if (recipe instanceof CraftRecipe) { - toAdd = (CraftRecipe) recipe; -@@ -1589,6 +1608,11 @@ public final class CraftServer implements Server { - } - } - toAdd.addToCraftingManager(); -+ // Paper start - API for updating recipes on clients -+ if (true || resendRecipes) { // Always needs to be resent now... TODO -+ this.playerList.reloadRecipeData(); -+ } -+ // Paper end - API for updating recipes on clients - return true; - } - -@@ -1769,9 +1793,23 @@ public final class CraftServer implements Server { - - @Override - public boolean removeRecipe(NamespacedKey recipeKey) { -+ // Paper start - API for updating recipes on clients -+ return this.removeRecipe(recipeKey, false); -+ } -+ -+ @Override -+ public boolean removeRecipe(NamespacedKey recipeKey, boolean resendRecipes) { -+ // Paper end - API for updating recipes on clients - Preconditions.checkArgument(recipeKey != null, "recipeKey == null"); - -- return this.getServer().getRecipeManager().removeRecipe(CraftRecipe.toMinecraft(recipeKey)); -+ // Paper start - resend recipes on successful removal -+ final ResourceKey> minecraftKey = CraftRecipe.toMinecraft(recipeKey); -+ final boolean removed = this.getServer().getRecipeManager().removeRecipe(minecraftKey); -+ if (removed/* && resendRecipes*/) { // TODO Always need to resend them rn - deprecate this method? -+ this.playerList.reloadRecipeData(); -+ } -+ return removed; -+ // Paper end - resend recipes on successful removal - } - - @Override diff --git a/patches/server/0845-Fix-custom-statistic-criteria-creation.patch b/patches/server/0845-Fix-custom-statistic-criteria-creation.patch new file mode 100644 index 0000000000..c57ac96255 --- /dev/null +++ b/patches/server/0845-Fix-custom-statistic-criteria-creation.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Sat, 12 Aug 2023 15:33:49 +0200 +Subject: [PATCH] Fix custom statistic criteria creation + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 9f4124485dac3d029ec8247b64098042aa1a48d2..a74784ddf63d316f253381ed803822a149e92bc7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -600,6 +600,12 @@ public final class CraftMagicNumbers implements UnsafeValues { + net.minecraft.core.Holder biomeBase = cra.getHandle().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME).getOrThrow(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.BIOME, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(biomeKey))); + cra.setBiome(x, y, z, biomeBase); + } ++ ++ @Override ++ public String getStatisticCriteriaKey(org.bukkit.Statistic statistic) { ++ if (statistic.getType() != org.bukkit.Statistic.Type.UNTYPED) return "minecraft.custom:minecraft." + statistic.getKey().getKey(); ++ return org.bukkit.craftbukkit.CraftStatistic.getNMSStatistic(statistic).getName(); ++ } + // Paper end + + /** diff --git a/patches/server/0846-Bandaid-fix-for-Effect.patch b/patches/server/0846-Bandaid-fix-for-Effect.patch new file mode 100644 index 0000000000..8c6534f28e --- /dev/null +++ b/patches/server/0846-Bandaid-fix-for-Effect.patch @@ -0,0 +1,179 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 28 Jul 2023 15:02:44 -0700 +Subject: [PATCH] Bandaid fix for Effect + +Effect or LevelEvent needs to be replaced +but ideally after the enum PR has been merged +upstream. Until then, this test and these fixes +should address all the known issues with them + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftEffect.java b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java +index 71733f918ed84b9879ac1b142ef6205c5e768a9c..c856384019eff2f2d0bb831ebe1ccb0fb9210782 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftEffect.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java +@@ -15,6 +15,14 @@ public class CraftEffect { + public static int getDataValue(Effect effect, T data) { + int datavalue; + switch (effect) { ++ // Paper start - add missing effects ++ case PARTICLES_SCULK_CHARGE: ++ case TRIAL_SPAWNER_DETECT_PLAYER: ++ case BEE_GROWTH: ++ case TURTLE_EGG_PLACEMENT: ++ case SMASH_ATTACK: ++ case TRIAL_SPAWNER_DETECT_PLAYER_OMINOUS: ++ // Paper end - add missing effects + case VILLAGER_PLANT_GROW: + datavalue = (Integer) data; + break; +@@ -26,6 +34,13 @@ public class CraftEffect { + Preconditions.checkArgument(data == Material.AIR || ((Material) data).isRecord(), "Invalid record type for Material %s!", data); + datavalue = Item.getId(CraftItemType.bukkitToMinecraft((Material) data)); + break; ++ // Paper start - handle shoot white smoke event ++ case SHOOT_WHITE_SMOKE: ++ final BlockFace face = (BlockFace) data; ++ Preconditions.checkArgument(face.isCartesian(), face + " isn't cartesian"); ++ datavalue = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(face).get3DDataValue(); ++ break; ++ // Paper end - handle shoot white smoke event + case SMOKE: + switch ((BlockFace) data) { + case DOWN: +@@ -57,10 +72,25 @@ public class CraftEffect { + } + break; + case STEP_SOUND: ++ if (data instanceof Material) { // Paper - support BlockData + Preconditions.checkArgument(((Material) data).isBlock(), "Material %s is not a block!", data); + datavalue = Block.getId(CraftBlockType.bukkitToMinecraft((Material) data).defaultBlockState()); ++ // Paper start - support BlockData ++ break; ++ } ++ case PARTICLES_AND_SOUND_BRUSH_BLOCK_COMPLETE: ++ datavalue = Block.getId(((org.bukkit.craftbukkit.block.data.CraftBlockData) data).getState()); ++ // Paper end + break; + case COMPOSTER_FILL_ATTEMPT: ++ // Paper start - add missing effects ++ case TRIAL_SPAWNER_SPAWN: ++ case TRIAL_SPAWNER_SPAWN_MOB_AT: ++ case VAULT_ACTIVATE: ++ case VAULT_DEACTIVATE: ++ case TRIAL_SPAWNER_BECOME_OMINOUS: ++ case TRIAL_SPAWNER_SPAWN_ITEM: ++ // Paper end - add missing effects + datavalue = ((Boolean) data) ? 1 : 0; + break; + case BONE_MEAL_USE: +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index c0f5e4497e1ffc93f56fc2b5748bcf76569e8c3a..188bd33f46b6baaa3fc21c9da6fa9a9d004e899e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1382,7 +1382,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + public void playEffect(Location loc, Effect effect, T data, int radius) { + if (data != null) { + Preconditions.checkArgument(effect.getData() != null, "Effect.%s does not have a valid Data", effect); +- Preconditions.checkArgument(effect.getData().isAssignableFrom(data.getClass()), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); ++ Preconditions.checkArgument(effect.isApplicable(data), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); // Paper + } else { + // Special case: the axis is optional for ELECTRIC_SPARK + Preconditions.checkArgument(effect.getData() == null || effect == Effect.ELECTRIC_SPARK, "Wrong kind of data for the %s effect", effect); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index ccf2c23ecf6f406ae07a2d7614d52e65da8ca586..80877e62d0743891f38abeee5b5b04b4f3bc4010 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -934,7 +934,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + Preconditions.checkArgument(effect != null, "Effect cannot be null"); + if (data != null) { + Preconditions.checkArgument(effect.getData() != null, "Effect.%s does not have a valid Data", effect); +- Preconditions.checkArgument(effect.getData().isAssignableFrom(data.getClass()), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); ++ Preconditions.checkArgument(effect.isApplicable(data), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); // Paper + } else { + // Special case: the axis is optional for ELECTRIC_SPARK + Preconditions.checkArgument(effect.getData() == null || effect == Effect.ELECTRIC_SPARK, "Wrong kind of data for the %s effect", effect); +diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3129212415c151aa028995b6e698f81b638e4c35 +--- /dev/null ++++ b/src/test/java/org/bukkit/EffectTest.java +@@ -0,0 +1,78 @@ ++package org.bukkit; ++ ++import com.google.common.base.Joiner; ++import java.lang.reflect.Field; ++import java.lang.reflect.Modifier; ++import java.util.ArrayList; ++import java.util.HashMap; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Map; ++import java.util.Set; ++import net.minecraft.world.level.block.LevelEvent; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertNotNull; ++import static org.junit.jupiter.api.Assertions.assertNull; ++import static org.junit.jupiter.api.Assertions.assertTrue; ++import static org.junit.jupiter.api.Assertions.fail; ++ ++public class EffectTest { ++ ++ private static List collectNmsLevelEvents() throws ReflectiveOperationException { ++ final List events = new ArrayList<>(); ++ for (final Field field : LevelEvent.class.getFields()) { ++ if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.getType() == int.class) { ++ events.add((int) field.get(null)); ++ } ++ } ++ return events; ++ } ++ ++ private static boolean isNotDeprecated(Effect effect) throws ReflectiveOperationException { ++ return !Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class); ++ } ++ ++ @Test ++ public void checkAllApiExists() throws ReflectiveOperationException { ++ Map toId = new HashMap<>(); ++ for (final Effect effect : Effect.values()) { ++ if (isNotDeprecated(effect)) { ++ final Effect put = toId.put(effect.getId(), effect); ++ assertNull(put, "duplicate API effect: " + put); ++ } ++ } ++ ++ final Set missingEvents = new HashSet<>(); ++ for (final Integer event : collectNmsLevelEvents()) { ++ if (toId.get(event) == null) { ++ missingEvents.add(event); ++ } ++ } ++ if (!missingEvents.isEmpty()) { ++ fail("Missing API Effects:\n" + Joiner.on("\n").join(missingEvents)); ++ } ++ } ++ ++ @Test ++ public void checkNoExtraApi() throws ReflectiveOperationException { ++ Map toId = new HashMap<>(); ++ for (final Effect effect : Effect.values()) { ++ if (isNotDeprecated(effect)) { ++ final Effect put = toId.put(effect.getId(), effect); ++ assertNull(put, "duplicate API effect: " + put); ++ } ++ } ++ ++ final List nmsEvents = collectNmsLevelEvents(); ++ final Set extraApiEffects = new HashSet<>(); ++ for (final Map.Entry entry : toId.entrySet()) { ++ if (!nmsEvents.contains(entry.getKey())) { ++ extraApiEffects.add(entry.getValue()); ++ } ++ } ++ if (!extraApiEffects.isEmpty()) { ++ fail("Extra API Effects:\n" + Joiner.on("\n").join(extraApiEffects)); ++ } ++ } ++} diff --git a/patches/server/0846-Fix-custom-statistic-criteria-creation.patch b/patches/server/0846-Fix-custom-statistic-criteria-creation.patch deleted file mode 100644 index 420f7179e9..0000000000 --- a/patches/server/0846-Fix-custom-statistic-criteria-creation.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Sat, 12 Aug 2023 15:33:49 +0200 -Subject: [PATCH] Fix custom statistic criteria creation - - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 9e0af05e066132b66fafff84ff0a0957c1a44f9f..766ef49d72eef0ff80247a807db5379f7fc60302 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -599,6 +599,14 @@ public final class CraftMagicNumbers implements UnsafeValues { - } - // Paper end - namespaced key biome methods - -+ // Paper start - fix custom stats criteria creation -+ @Override -+ public String getStatisticCriteriaKey(org.bukkit.Statistic statistic) { -+ if (statistic.getType() != org.bukkit.Statistic.Type.UNTYPED) return "minecraft.custom:minecraft." + statistic.getKey().getKey(); -+ return org.bukkit.craftbukkit.CraftStatistic.getNMSStatistic(statistic).getName(); -+ } -+ // Paper end - fix custom stats criteria creation -+ - @Override - public String get(Class aClass, String s) { - if (aClass == Enchantment.class) { diff --git a/patches/server/0847-Bandaid-fix-for-Effect.patch b/patches/server/0847-Bandaid-fix-for-Effect.patch deleted file mode 100644 index 8c6534f28e..0000000000 --- a/patches/server/0847-Bandaid-fix-for-Effect.patch +++ /dev/null @@ -1,179 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 28 Jul 2023 15:02:44 -0700 -Subject: [PATCH] Bandaid fix for Effect - -Effect or LevelEvent needs to be replaced -but ideally after the enum PR has been merged -upstream. Until then, this test and these fixes -should address all the known issues with them - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftEffect.java b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java -index 71733f918ed84b9879ac1b142ef6205c5e768a9c..c856384019eff2f2d0bb831ebe1ccb0fb9210782 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftEffect.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftEffect.java -@@ -15,6 +15,14 @@ public class CraftEffect { - public static int getDataValue(Effect effect, T data) { - int datavalue; - switch (effect) { -+ // Paper start - add missing effects -+ case PARTICLES_SCULK_CHARGE: -+ case TRIAL_SPAWNER_DETECT_PLAYER: -+ case BEE_GROWTH: -+ case TURTLE_EGG_PLACEMENT: -+ case SMASH_ATTACK: -+ case TRIAL_SPAWNER_DETECT_PLAYER_OMINOUS: -+ // Paper end - add missing effects - case VILLAGER_PLANT_GROW: - datavalue = (Integer) data; - break; -@@ -26,6 +34,13 @@ public class CraftEffect { - Preconditions.checkArgument(data == Material.AIR || ((Material) data).isRecord(), "Invalid record type for Material %s!", data); - datavalue = Item.getId(CraftItemType.bukkitToMinecraft((Material) data)); - break; -+ // Paper start - handle shoot white smoke event -+ case SHOOT_WHITE_SMOKE: -+ final BlockFace face = (BlockFace) data; -+ Preconditions.checkArgument(face.isCartesian(), face + " isn't cartesian"); -+ datavalue = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(face).get3DDataValue(); -+ break; -+ // Paper end - handle shoot white smoke event - case SMOKE: - switch ((BlockFace) data) { - case DOWN: -@@ -57,10 +72,25 @@ public class CraftEffect { - } - break; - case STEP_SOUND: -+ if (data instanceof Material) { // Paper - support BlockData - Preconditions.checkArgument(((Material) data).isBlock(), "Material %s is not a block!", data); - datavalue = Block.getId(CraftBlockType.bukkitToMinecraft((Material) data).defaultBlockState()); -+ // Paper start - support BlockData -+ break; -+ } -+ case PARTICLES_AND_SOUND_BRUSH_BLOCK_COMPLETE: -+ datavalue = Block.getId(((org.bukkit.craftbukkit.block.data.CraftBlockData) data).getState()); -+ // Paper end - break; - case COMPOSTER_FILL_ATTEMPT: -+ // Paper start - add missing effects -+ case TRIAL_SPAWNER_SPAWN: -+ case TRIAL_SPAWNER_SPAWN_MOB_AT: -+ case VAULT_ACTIVATE: -+ case VAULT_DEACTIVATE: -+ case TRIAL_SPAWNER_BECOME_OMINOUS: -+ case TRIAL_SPAWNER_SPAWN_ITEM: -+ // Paper end - add missing effects - datavalue = ((Boolean) data) ? 1 : 0; - break; - case BONE_MEAL_USE: -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index c0f5e4497e1ffc93f56fc2b5748bcf76569e8c3a..188bd33f46b6baaa3fc21c9da6fa9a9d004e899e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1382,7 +1382,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - public void playEffect(Location loc, Effect effect, T data, int radius) { - if (data != null) { - Preconditions.checkArgument(effect.getData() != null, "Effect.%s does not have a valid Data", effect); -- Preconditions.checkArgument(effect.getData().isAssignableFrom(data.getClass()), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); -+ Preconditions.checkArgument(effect.isApplicable(data), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); // Paper - } else { - // Special case: the axis is optional for ELECTRIC_SPARK - Preconditions.checkArgument(effect.getData() == null || effect == Effect.ELECTRIC_SPARK, "Wrong kind of data for the %s effect", effect); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index ccf2c23ecf6f406ae07a2d7614d52e65da8ca586..80877e62d0743891f38abeee5b5b04b4f3bc4010 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -934,7 +934,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - Preconditions.checkArgument(effect != null, "Effect cannot be null"); - if (data != null) { - Preconditions.checkArgument(effect.getData() != null, "Effect.%s does not have a valid Data", effect); -- Preconditions.checkArgument(effect.getData().isAssignableFrom(data.getClass()), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); -+ Preconditions.checkArgument(effect.isApplicable(data), "%s data cannot be used for the %s effect", data.getClass().getName(), effect); // Paper - } else { - // Special case: the axis is optional for ELECTRIC_SPARK - Preconditions.checkArgument(effect.getData() == null || effect == Effect.ELECTRIC_SPARK, "Wrong kind of data for the %s effect", effect); -diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3129212415c151aa028995b6e698f81b638e4c35 ---- /dev/null -+++ b/src/test/java/org/bukkit/EffectTest.java -@@ -0,0 +1,78 @@ -+package org.bukkit; -+ -+import com.google.common.base.Joiner; -+import java.lang.reflect.Field; -+import java.lang.reflect.Modifier; -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+import net.minecraft.world.level.block.LevelEvent; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertNotNull; -+import static org.junit.jupiter.api.Assertions.assertNull; -+import static org.junit.jupiter.api.Assertions.assertTrue; -+import static org.junit.jupiter.api.Assertions.fail; -+ -+public class EffectTest { -+ -+ private static List collectNmsLevelEvents() throws ReflectiveOperationException { -+ final List events = new ArrayList<>(); -+ for (final Field field : LevelEvent.class.getFields()) { -+ if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.getType() == int.class) { -+ events.add((int) field.get(null)); -+ } -+ } -+ return events; -+ } -+ -+ private static boolean isNotDeprecated(Effect effect) throws ReflectiveOperationException { -+ return !Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class); -+ } -+ -+ @Test -+ public void checkAllApiExists() throws ReflectiveOperationException { -+ Map toId = new HashMap<>(); -+ for (final Effect effect : Effect.values()) { -+ if (isNotDeprecated(effect)) { -+ final Effect put = toId.put(effect.getId(), effect); -+ assertNull(put, "duplicate API effect: " + put); -+ } -+ } -+ -+ final Set missingEvents = new HashSet<>(); -+ for (final Integer event : collectNmsLevelEvents()) { -+ if (toId.get(event) == null) { -+ missingEvents.add(event); -+ } -+ } -+ if (!missingEvents.isEmpty()) { -+ fail("Missing API Effects:\n" + Joiner.on("\n").join(missingEvents)); -+ } -+ } -+ -+ @Test -+ public void checkNoExtraApi() throws ReflectiveOperationException { -+ Map toId = new HashMap<>(); -+ for (final Effect effect : Effect.values()) { -+ if (isNotDeprecated(effect)) { -+ final Effect put = toId.put(effect.getId(), effect); -+ assertNull(put, "duplicate API effect: " + put); -+ } -+ } -+ -+ final List nmsEvents = collectNmsLevelEvents(); -+ final Set extraApiEffects = new HashSet<>(); -+ for (final Map.Entry entry : toId.entrySet()) { -+ if (!nmsEvents.contains(entry.getKey())) { -+ extraApiEffects.add(entry.getValue()); -+ } -+ } -+ if (!extraApiEffects.isEmpty()) { -+ fail("Extra API Effects:\n" + Joiner.on("\n").join(extraApiEffects)); -+ } -+ } -+} diff --git a/patches/server/0847-SculkCatalyst-bloom-API.patch b/patches/server/0847-SculkCatalyst-bloom-API.patch new file mode 100644 index 0000000000..ba050f6086 --- /dev/null +++ b/patches/server/0847-SculkCatalyst-bloom-API.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Oliwier Miodun +Date: Mon, 10 Jul 2023 17:59:42 +0200 +Subject: [PATCH] SculkCatalyst bloom API + +== AT == +public net.minecraft.world.level.block.entity.SculkCatalystBlockEntity$CatalystListener bloom(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/util/RandomSource;)V + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java +index 5211dc80f449cec09f992a42667e869ab9e7115e..407d5b1d87d14e18878f0ebf1d676a7f49e7cfaf 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java +@@ -38,4 +38,20 @@ public class CraftSculkCatalyst extends CraftBlockEntityState +Date: Sun, 9 Jul 2023 11:55:02 -0700 +Subject: [PATCH] API for an entity's scoreboard name + +Was obtainable through different methods, but you had to use different +methods depending on the implementation of Entity you were working with. + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index df199c1cffa7795126ab83af67e184238ddb211d..dd84f7d6874a799aa09349fe0a1bd6ebb4cea2dd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1264,4 +1264,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return !this.getHandle().level().noCollision(this.getHandle(), aabb); + } + // Paper end - Collision API ++ ++ // Paper start - entity scoreboard name ++ @Override ++ public String getScoreboardEntryName() { ++ return this.getHandle().getScoreboardName(); ++ } ++ // Paper end - entity scoreboard name + } diff --git a/patches/server/0848-SculkCatalyst-bloom-API.patch b/patches/server/0848-SculkCatalyst-bloom-API.patch deleted file mode 100644 index ba050f6086..0000000000 --- a/patches/server/0848-SculkCatalyst-bloom-API.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Oliwier Miodun -Date: Mon, 10 Jul 2023 17:59:42 +0200 -Subject: [PATCH] SculkCatalyst bloom API - -== AT == -public net.minecraft.world.level.block.entity.SculkCatalystBlockEntity$CatalystListener bloom(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/util/RandomSource;)V - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java -index 5211dc80f449cec09f992a42667e869ab9e7115e..407d5b1d87d14e18878f0ebf1d676a7f49e7cfaf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkCatalyst.java -@@ -38,4 +38,20 @@ public class CraftSculkCatalyst extends CraftBlockEntityState -Date: Sun, 9 Jul 2023 11:55:02 -0700 -Subject: [PATCH] API for an entity's scoreboard name - -Was obtainable through different methods, but you had to use different -methods depending on the implementation of Entity you were working with. - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index df199c1cffa7795126ab83af67e184238ddb211d..dd84f7d6874a799aa09349fe0a1bd6ebb4cea2dd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1264,4 +1264,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return !this.getHandle().level().noCollision(this.getHandle(), aabb); - } - // Paper end - Collision API -+ -+ // Paper start - entity scoreboard name -+ @Override -+ public String getScoreboardEntryName() { -+ return this.getHandle().getScoreboardName(); -+ } -+ // Paper end - entity scoreboard name - } diff --git a/patches/server/0849-Deprecate-and-replace-methods-with-old-StructureType.patch b/patches/server/0849-Deprecate-and-replace-methods-with-old-StructureType.patch new file mode 100644 index 0000000000..80817c1175 --- /dev/null +++ b/patches/server/0849-Deprecate-and-replace-methods-with-old-StructureType.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 10 Dec 2022 17:52:38 -0800 +Subject: [PATCH] Deprecate and replace methods with old StructureType + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index fa505c0714bb95b2ab08b4bbb9ea79ce98898f4b..a1f2c8fd0348a6a5dad521430f473867bdadd1a5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2007,6 +2007,11 @@ public final class CraftServer implements Server { + + ServerLevel worldServer = ((CraftWorld) world).getHandle(); + Location structureLocation = world.locateNearestStructure(location, structureType, radius, findUnexplored); ++ // Paper start - don't throw NPE ++ if (structureLocation == null) { ++ throw new IllegalStateException("Could not find a structure for " + structureType); ++ } ++ // Paper end + BlockPos structurePosition = CraftLocation.toBlockPosition(structureLocation); + + // Create map with trackPlayer = true, unlimitedTracking = true +@@ -2017,6 +2022,31 @@ public final class CraftServer implements Server { + + return CraftItemStack.asBukkitCopy(stack); + } ++ // Paper start - copied from above (uses un-deprecated StructureType type) ++ @Override ++ public ItemStack createExplorerMap(World world, Location location, org.bukkit.generator.structure.StructureType structureType, org.bukkit.map.MapCursor.Type mapIcon, int radius, boolean findUnexplored) { ++ Preconditions.checkArgument(world != null, "World cannot be null"); ++ Preconditions.checkArgument(location != null, "Location cannot be null"); ++ Preconditions.checkArgument(structureType != null, "StructureType cannot be null"); ++ Preconditions.checkArgument(mapIcon != null, "mapIcon cannot be null"); ++ ++ ServerLevel worldServer = ((CraftWorld) world).getHandle(); ++ final org.bukkit.util.StructureSearchResult structureSearchResult = world.locateNearestStructure(location, structureType, radius, findUnexplored); ++ if (structureSearchResult == null) { ++ return null; ++ } ++ Location structureLocation = structureSearchResult.getLocation(); ++ BlockPos structurePosition = new BlockPos(structureLocation.getBlockX(), structureLocation.getBlockY(), structureLocation.getBlockZ()); ++ ++ // Create map with showIcons = true, unlimitedTracking = true ++ net.minecraft.world.item.ItemStack stack = MapItem.create(worldServer, structurePosition.getX(), structurePosition.getZ(), MapView.Scale.NORMAL.getValue(), true, true); ++ MapItem.renderBiomePreviewMap(worldServer, stack); ++ // "+" map ID taken from VillagerTrades$TreasureMapForEmeralds ++ MapItem.getSavedData(stack, worldServer).addTargetDecoration(stack, structurePosition, "+", CraftMapCursor.CraftType.bukkitToMinecraftHolder(mapIcon)); ++ ++ return CraftItemStack.asBukkitCopy(stack); ++ } ++ // Paper end + + @Override + public void shutdown() { diff --git a/patches/server/0850-Deprecate-and-replace-methods-with-old-StructureType.patch b/patches/server/0850-Deprecate-and-replace-methods-with-old-StructureType.patch deleted file mode 100644 index 82cc3b4373..0000000000 --- a/patches/server/0850-Deprecate-and-replace-methods-with-old-StructureType.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 10 Dec 2022 17:52:38 -0800 -Subject: [PATCH] Deprecate and replace methods with old StructureType - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 0433de3c2455cf18584d5ab651843f8d1d874036..83c3de4ae733199f64fe0f967f9f816545d20f1c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2008,6 +2008,11 @@ public final class CraftServer implements Server { - - ServerLevel worldServer = ((CraftWorld) world).getHandle(); - Location structureLocation = world.locateNearestStructure(location, structureType, radius, findUnexplored); -+ // Paper start - don't throw NPE -+ if (structureLocation == null) { -+ throw new IllegalStateException("Could not find a structure for " + structureType); -+ } -+ // Paper end - BlockPos structurePosition = CraftLocation.toBlockPosition(structureLocation); - - // Create map with trackPlayer = true, unlimitedTracking = true -@@ -2018,6 +2023,31 @@ public final class CraftServer implements Server { - - return CraftItemStack.asBukkitCopy(stack); - } -+ // Paper start - copied from above (uses un-deprecated StructureType type) -+ @Override -+ public ItemStack createExplorerMap(World world, Location location, org.bukkit.generator.structure.StructureType structureType, org.bukkit.map.MapCursor.Type mapIcon, int radius, boolean findUnexplored) { -+ Preconditions.checkArgument(world != null, "World cannot be null"); -+ Preconditions.checkArgument(location != null, "Location cannot be null"); -+ Preconditions.checkArgument(structureType != null, "StructureType cannot be null"); -+ Preconditions.checkArgument(mapIcon != null, "mapIcon cannot be null"); -+ -+ ServerLevel worldServer = ((CraftWorld) world).getHandle(); -+ final org.bukkit.util.StructureSearchResult structureSearchResult = world.locateNearestStructure(location, structureType, radius, findUnexplored); -+ if (structureSearchResult == null) { -+ return null; -+ } -+ Location structureLocation = structureSearchResult.getLocation(); -+ BlockPos structurePosition = new BlockPos(structureLocation.getBlockX(), structureLocation.getBlockY(), structureLocation.getBlockZ()); -+ -+ // Create map with showIcons = true, unlimitedTracking = true -+ net.minecraft.world.item.ItemStack stack = MapItem.create(worldServer, structurePosition.getX(), structurePosition.getZ(), MapView.Scale.NORMAL.getValue(), true, true); -+ MapItem.renderBiomePreviewMap(worldServer, stack); -+ // "+" map ID taken from VillagerTrades$TreasureMapForEmeralds -+ MapItem.getSavedData(stack, worldServer).addTargetDecoration(stack, structurePosition, "+", CraftMapCursor.CraftType.bukkitToMinecraftHolder(mapIcon)); -+ -+ return CraftItemStack.asBukkitCopy(stack); -+ } -+ // Paper end - - @Override - public void shutdown() { diff --git a/patches/server/0850-Don-t-tab-complete-namespaced-commands-if-send-names.patch b/patches/server/0850-Don-t-tab-complete-namespaced-commands-if-send-names.patch new file mode 100644 index 0000000000..8834a03dcb --- /dev/null +++ b/patches/server/0850-Don-t-tab-complete-namespaced-commands-if-send-names.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: EpicPlayerA10 +Date: Sun, 18 Jun 2023 12:38:24 +0200 +Subject: [PATCH] Don't tab-complete namespaced commands if send-namespaced is + false + +Tab-complete packet is supposed to tab-complete args for commands, but +it also can suggest commands like in version 1.12.2 or lower. + +This patch prevents server from sending namespaced commands when player +requests tab-complete only commands. + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 134d9fbdb757094a4624325c0ad8f32efadd61b6..688d6e51bc8b844ba7648cf1aed1bdd9629c1675 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -832,6 +832,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); + + this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { ++ // Paper start - Don't tab-complete namespaced commands if send-namespaced is false ++ if (!org.spigotmc.SpigotConfig.sendNamespaced && suggestions.getRange().getStart() <= 1) { ++ suggestions.getList().removeIf(suggestion -> suggestion.getText().contains(":")); ++ } ++ // Paper end - Don't tab-complete namespaced commands if send-namespaced is false + // Paper start - Brigadier API + com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); + suggestEvent.setCancelled(suggestions.isEmpty()); diff --git a/patches/server/0851-Don-t-tab-complete-namespaced-commands-if-send-names.patch b/patches/server/0851-Don-t-tab-complete-namespaced-commands-if-send-names.patch deleted file mode 100644 index 58454d7267..0000000000 --- a/patches/server/0851-Don-t-tab-complete-namespaced-commands-if-send-names.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: EpicPlayerA10 -Date: Sun, 18 Jun 2023 12:38:24 +0200 -Subject: [PATCH] Don't tab-complete namespaced commands if send-namespaced is - false - -Tab-complete packet is supposed to tab-complete args for commands, but -it also can suggest commands like in version 1.12.2 or lower. - -This patch prevents server from sending namespaced commands when player -requests tab-complete only commands. - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 368547270a3e6cdbda812fcf0ed2519d71383b81..293c42dd5e870986a2797840756bd7c4d6a34a5d 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -832,6 +832,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); - - this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { -+ // Paper start - Don't tab-complete namespaced commands if send-namespaced is false -+ if (!org.spigotmc.SpigotConfig.sendNamespaced && suggestions.getRange().getStart() <= 1) { -+ suggestions.getList().removeIf(suggestion -> suggestion.getText().contains(":")); -+ } -+ // Paper end - Don't tab-complete namespaced commands if send-namespaced is false - // Paper start - Brigadier API - com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); - suggestEvent.setCancelled(suggestions.isEmpty()); diff --git a/patches/server/0851-Properly-handle-BlockBreakEvent-isDropItems.patch b/patches/server/0851-Properly-handle-BlockBreakEvent-isDropItems.patch new file mode 100644 index 0000000000..7bf30bb112 --- /dev/null +++ b/patches/server/0851-Properly-handle-BlockBreakEvent-isDropItems.patch @@ -0,0 +1,162 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 4 Mar 2023 10:52:52 -0800 +Subject: [PATCH] Properly handle BlockBreakEvent#isDropItems + +Setting whether a block break dropped items controlled +far more than just whether blocks dropped, like stat increases +food consumption, turtle egg count decreases, ice to water +conversions and beehive releases + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 2aee9c2fbe38076317a3de7c3fdbd6988b64b389..3bd4ab8161c29bb8df2ba496a4430393b6593476 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -437,8 +437,8 @@ public class ServerPlayerGameMode { + isCorrectTool = flag1; // Paper - Trigger bee_nest_destroyed trigger in the correct place + + itemstack.mineBlock(this.level, iblockdata1, pos, this.player); +- if (flag && flag1 && event.isDropItems()) { // CraftBukkit - Check if block should drop items +- block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1); ++ if (flag && flag1/* && event.isDropItems() */) { // CraftBukkit - Check if block should drop items // Paper - fix drops not preventing stats/food exhaustion ++ block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1, event.isDropItems(), false); // Paper - fix drops not preventing stats/food exhaustion + } + + // return true; // CraftBukkit +diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java +index d5ed53c37bba79f84b60d616887cd5176e124f10..6c0ea0bde1c36edda92807e317ed37f8b1bdac6a 100644 +--- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java +@@ -94,8 +94,8 @@ public class BeehiveBlock extends BaseEntityBlock { + } + + @Override +- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { +- super.playerDestroy(world, player, pos, state, blockEntity, tool); ++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion ++ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion + if (!world.isClientSide && blockEntity instanceof BeehiveBlockEntity tileentitybeehive) { + if (!EnchantmentHelper.hasTag(tool, EnchantmentTags.PREVENTS_BEE_SPAWNS_WHEN_MINING)) { + tileentitybeehive.emptyAllLivingFromHive(player, state, BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY); +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index 9d8c4ecd89b05a0e5d4ebb5e686eba5d899765f2..4ff32e3fb1a1979827ef063cda196a43995440fe 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -396,10 +396,18 @@ public class Block extends BlockBehaviour implements ItemLike { + return this.defaultBlockState(); + } + ++ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - fix drops not preventing stats/food exhaustion + public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { ++ // Paper start - fix drops not preventing stats/food exhaustion ++ this.playerDestroy(world, player, pos, state, blockEntity, tool, true, true); ++ } ++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { ++ // Paper end - fix drops not preventing stats/food exhaustion + player.awardStat(Stats.BLOCK_MINED.get(this)); + player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent ++ if (includeDrops) { // Paper - fix drops not preventing stats/food exhaustion + Block.dropResources(state, world, pos, blockEntity, player, tool); ++ } // Paper - fix drops not preventing stats/food exhaustion + } + + public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {} +diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java +index edb3b6cdb617c48140539728af1373993e78648f..4fe83bd0f355549847b66afb7e61f6f2a6d97016 100644 +--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java +@@ -98,8 +98,8 @@ public class DoublePlantBlock extends BushBlock { + } + + @Override +- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { +- super.playerDestroy(world, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool); ++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion ++ super.playerDestroy(world, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion + } + + protected static void preventDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) { +diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java +index 067a2d969ca0979ae67b600e303deec93eda0251..a94762e65853ccad38cf90b0049ca256106c0c9f 100644 +--- a/src/main/java/net/minecraft/world/level/block/IceBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java +@@ -34,8 +34,8 @@ public class IceBlock extends HalfTransparentBlock { + } + + @Override +- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { +- super.playerDestroy(world, player, pos, state, blockEntity, tool); ++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion ++ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion + // Paper start - Improve Block#breakNaturally API + this.afterDestroy(world, pos, tool); + } +diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java +index 85d9829e979ef5f22aee9c346800612f479786b7..953ddb2ea6fd48e57712e30a6addf23e188e5312 100644 +--- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java +@@ -175,8 +175,8 @@ public class TurtleEggBlock extends Block { + } + + @Override +- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { +- super.playerDestroy(world, player, pos, state, blockEntity, tool); ++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion ++ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion + this.decreaseEggs(world, pos, state); + } + +diff --git a/src/test/java/io/papermc/paper/world/block/BlockPlayerDestroyOverrideTest.java b/src/test/java/io/papermc/paper/world/block/BlockPlayerDestroyOverrideTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..22145bf698b3d1ff0a07a3aaa8d55a19905f99ad +--- /dev/null ++++ b/src/test/java/io/papermc/paper/world/block/BlockPlayerDestroyOverrideTest.java +@@ -0,0 +1,48 @@ ++package io.papermc.paper.world.block; ++ ++import io.github.classgraph.ClassGraph; ++import io.github.classgraph.ClassInfo; ++import io.github.classgraph.MethodInfo; ++import io.github.classgraph.MethodInfoList; ++import io.github.classgraph.MethodParameterInfo; ++import io.github.classgraph.ScanResult; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.stream.Stream; ++import org.bukkit.support.environment.Normal; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++ ++@Normal ++public class BlockPlayerDestroyOverrideTest { ++ ++ public static Stream parameters() { ++ final List classInfo = new ArrayList<>(); ++ try (ScanResult scanResult = new ClassGraph() ++ .enableClassInfo() ++ .enableMethodInfo() ++ .whitelistPackages("net.minecraft") ++ .scan() ++ ) { ++ for (final ClassInfo subclass : scanResult.getSubclasses("net.minecraft.world.level.block.Block")) { ++ final MethodInfoList playerDestroy = subclass.getDeclaredMethodInfo("playerDestroy"); ++ if (!playerDestroy.isEmpty()) { ++ classInfo.add(subclass); ++ } ++ } ++ } ++ return classInfo.stream(); ++ } ++ ++ @ParameterizedTest ++ @MethodSource("parameters") ++ public void checkPlayerDestroyOverrides(ClassInfo overridesPlayerDestroy) { ++ final MethodInfoList playerDestroy = overridesPlayerDestroy.getDeclaredMethodInfo("playerDestroy"); ++ assertEquals(1, playerDestroy.size(), overridesPlayerDestroy.getName() + " has multiple playerDestroy methods"); ++ final MethodInfo next = playerDestroy.iterator().next(); ++ final MethodParameterInfo[] parameterInfo = next.getParameterInfo(); ++ assertEquals("boolean", parameterInfo[parameterInfo.length - 1].getTypeDescriptor().toStringWithSimpleNames(), overridesPlayerDestroy.getName() + " needs to change its override of playerDestroy"); ++ } ++} diff --git a/patches/server/0852-Fire-entity-death-event-for-ender-dragon.patch b/patches/server/0852-Fire-entity-death-event-for-ender-dragon.patch new file mode 100644 index 0000000000..0efcc781a4 --- /dev/null +++ b/patches/server/0852-Fire-entity-death-event-for-ender-dragon.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trevor Bedson <78997566+Prorickey@users.noreply.github.com> +Date: Fri, 14 Jul 2023 20:47:02 -0400 +Subject: [PATCH] Fire entity death event for ender dragon + + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +index 38456d3901e495e4c401cff0de7ae38544c1b2a7..2df8bf818345246cc1f88b93e4a3b62e61772efb 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +@@ -627,6 +627,14 @@ public class EnderDragon extends Mob implements Enemy { + + @Override + public void kill(ServerLevel world) { ++ // Paper start - Fire entity death event ++ this.silentDeath = true; ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, this.damageSources().genericKill()); ++ if (deathEvent.isCancelled()) { ++ this.silentDeath = false; // Reset to default if event was cancelled ++ return; ++ } ++ // Paper end - Fire entity death event + this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause + this.gameEvent(GameEvent.ENTITY_DIE); + if (this.dragonFight != null) { diff --git a/patches/server/0852-Properly-handle-BlockBreakEvent-isDropItems.patch b/patches/server/0852-Properly-handle-BlockBreakEvent-isDropItems.patch deleted file mode 100644 index 6c61a65a1c..0000000000 --- a/patches/server/0852-Properly-handle-BlockBreakEvent-isDropItems.patch +++ /dev/null @@ -1,162 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 4 Mar 2023 10:52:52 -0800 -Subject: [PATCH] Properly handle BlockBreakEvent#isDropItems - -Setting whether a block break dropped items controlled -far more than just whether blocks dropped, like stat increases -food consumption, turtle egg count decreases, ice to water -conversions and beehive releases - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 2aee9c2fbe38076317a3de7c3fdbd6988b64b389..3bd4ab8161c29bb8df2ba496a4430393b6593476 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -437,8 +437,8 @@ public class ServerPlayerGameMode { - isCorrectTool = flag1; // Paper - Trigger bee_nest_destroyed trigger in the correct place - - itemstack.mineBlock(this.level, iblockdata1, pos, this.player); -- if (flag && flag1 && event.isDropItems()) { // CraftBukkit - Check if block should drop items -- block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1); -+ if (flag && flag1/* && event.isDropItems() */) { // CraftBukkit - Check if block should drop items // Paper - fix drops not preventing stats/food exhaustion -+ block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1, event.isDropItems(), false); // Paper - fix drops not preventing stats/food exhaustion - } - - // return true; // CraftBukkit -diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -index d5ed53c37bba79f84b60d616887cd5176e124f10..6c0ea0bde1c36edda92807e317ed37f8b1bdac6a 100644 ---- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -@@ -94,8 +94,8 @@ public class BeehiveBlock extends BaseEntityBlock { - } - - @Override -- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { -- super.playerDestroy(world, player, pos, state, blockEntity, tool); -+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion - if (!world.isClientSide && blockEntity instanceof BeehiveBlockEntity tileentitybeehive) { - if (!EnchantmentHelper.hasTag(tool, EnchantmentTags.PREVENTS_BEE_SPAWNS_WHEN_MINING)) { - tileentitybeehive.emptyAllLivingFromHive(player, state, BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY); -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 4d140bd83ca0e1554afad80ec4fc6186188a79d8..6fb3f551f432d7e668c606fb7bd3514408e0478a 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -405,10 +405,18 @@ public class Block extends BlockBehaviour implements ItemLike { - return this.defaultBlockState(); - } - -+ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - fix drops not preventing stats/food exhaustion - public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { -+ // Paper start - fix drops not preventing stats/food exhaustion -+ this.playerDestroy(world, player, pos, state, blockEntity, tool, true, true); -+ } -+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { -+ // Paper end - fix drops not preventing stats/food exhaustion - player.awardStat(Stats.BLOCK_MINED.get(this)); - player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent -+ if (includeDrops) { // Paper - fix drops not preventing stats/food exhaustion - Block.dropResources(state, world, pos, blockEntity, player, tool); -+ } // Paper - fix drops not preventing stats/food exhaustion - } - - public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {} -diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java -index edb3b6cdb617c48140539728af1373993e78648f..4fe83bd0f355549847b66afb7e61f6f2a6d97016 100644 ---- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java -@@ -98,8 +98,8 @@ public class DoublePlantBlock extends BushBlock { - } - - @Override -- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { -- super.playerDestroy(world, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool); -+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(world, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion - } - - protected static void preventDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) { -diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java -index 067a2d969ca0979ae67b600e303deec93eda0251..a94762e65853ccad38cf90b0049ca256106c0c9f 100644 ---- a/src/main/java/net/minecraft/world/level/block/IceBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java -@@ -34,8 +34,8 @@ public class IceBlock extends HalfTransparentBlock { - } - - @Override -- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { -- super.playerDestroy(world, player, pos, state, blockEntity, tool); -+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion - // Paper start - Improve Block#breakNaturally API - this.afterDestroy(world, pos, tool); - } -diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -index 85d9829e979ef5f22aee9c346800612f479786b7..953ddb2ea6fd48e57712e30a6addf23e188e5312 100644 ---- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -@@ -175,8 +175,8 @@ public class TurtleEggBlock extends Block { - } - - @Override -- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { -- super.playerDestroy(world, player, pos, state, blockEntity, tool); -+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion - this.decreaseEggs(world, pos, state); - } - -diff --git a/src/test/java/io/papermc/paper/world/block/BlockPlayerDestroyOverrideTest.java b/src/test/java/io/papermc/paper/world/block/BlockPlayerDestroyOverrideTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..22145bf698b3d1ff0a07a3aaa8d55a19905f99ad ---- /dev/null -+++ b/src/test/java/io/papermc/paper/world/block/BlockPlayerDestroyOverrideTest.java -@@ -0,0 +1,48 @@ -+package io.papermc.paper.world.block; -+ -+import io.github.classgraph.ClassGraph; -+import io.github.classgraph.ClassInfo; -+import io.github.classgraph.MethodInfo; -+import io.github.classgraph.MethodInfoList; -+import io.github.classgraph.MethodParameterInfo; -+import io.github.classgraph.ScanResult; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.stream.Stream; -+import org.bukkit.support.environment.Normal; -+import org.junit.jupiter.params.ParameterizedTest; -+import org.junit.jupiter.params.provider.MethodSource; -+ -+import static org.junit.jupiter.api.Assertions.assertEquals; -+ -+@Normal -+public class BlockPlayerDestroyOverrideTest { -+ -+ public static Stream parameters() { -+ final List classInfo = new ArrayList<>(); -+ try (ScanResult scanResult = new ClassGraph() -+ .enableClassInfo() -+ .enableMethodInfo() -+ .whitelistPackages("net.minecraft") -+ .scan() -+ ) { -+ for (final ClassInfo subclass : scanResult.getSubclasses("net.minecraft.world.level.block.Block")) { -+ final MethodInfoList playerDestroy = subclass.getDeclaredMethodInfo("playerDestroy"); -+ if (!playerDestroy.isEmpty()) { -+ classInfo.add(subclass); -+ } -+ } -+ } -+ return classInfo.stream(); -+ } -+ -+ @ParameterizedTest -+ @MethodSource("parameters") -+ public void checkPlayerDestroyOverrides(ClassInfo overridesPlayerDestroy) { -+ final MethodInfoList playerDestroy = overridesPlayerDestroy.getDeclaredMethodInfo("playerDestroy"); -+ assertEquals(1, playerDestroy.size(), overridesPlayerDestroy.getName() + " has multiple playerDestroy methods"); -+ final MethodInfo next = playerDestroy.iterator().next(); -+ final MethodParameterInfo[] parameterInfo = next.getParameterInfo(); -+ assertEquals("boolean", parameterInfo[parameterInfo.length - 1].getTypeDescriptor().toStringWithSimpleNames(), overridesPlayerDestroy.getName() + " needs to change its override of playerDestroy"); -+ } -+} diff --git a/patches/server/0853-Configurable-entity-tracking-range-by-Y-coordinate.patch b/patches/server/0853-Configurable-entity-tracking-range-by-Y-coordinate.patch new file mode 100644 index 0000000000..a8f7a157ae --- /dev/null +++ b/patches/server/0853-Configurable-entity-tracking-range-by-Y-coordinate.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ruViolence <78062896+ruViolence@users.noreply.github.com> +Date: Tue, 27 Jun 2023 15:38:18 +0800 +Subject: [PATCH] Configurable entity tracking range by Y coordinate + +Options to configure entity tracking by Y coordinate, also for each entity category. + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 53e180e230d5a1652f3e19193243c37095d6b39e..5da3eee41ba0cbec5932cf9a7dac53777a2463fb 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1577,7 +1577,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + double d0 = (double) Math.min(this.getEffectiveRange(), i * 16); + double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; + double d2 = d0 * d0; +- boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); ++ // Paper start - Configurable entity tracking range by Y ++ boolean flag = d1 <= d2; ++ if (flag && level.paperConfig().entities.trackingRangeY.enabled) { ++ double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1); ++ if (rangeY != -1) { ++ double vec3d_dy = player.getY() - this.entity.getY(); ++ flag = vec3d_dy * vec3d_dy <= rangeY * rangeY; ++ } ++ } ++ flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); ++ // Paper end - Configurable entity tracking range by Y + + // CraftBukkit start - respect vanish API + if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { diff --git a/patches/server/0853-Fire-entity-death-event-for-ender-dragon.patch b/patches/server/0853-Fire-entity-death-event-for-ender-dragon.patch deleted file mode 100644 index 0efcc781a4..0000000000 --- a/patches/server/0853-Fire-entity-death-event-for-ender-dragon.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trevor Bedson <78997566+Prorickey@users.noreply.github.com> -Date: Fri, 14 Jul 2023 20:47:02 -0400 -Subject: [PATCH] Fire entity death event for ender dragon - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index 38456d3901e495e4c401cff0de7ae38544c1b2a7..2df8bf818345246cc1f88b93e4a3b62e61772efb 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -@@ -627,6 +627,14 @@ public class EnderDragon extends Mob implements Enemy { - - @Override - public void kill(ServerLevel world) { -+ // Paper start - Fire entity death event -+ this.silentDeath = true; -+ org.bukkit.event.entity.EntityDeathEvent deathEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, this.damageSources().genericKill()); -+ if (deathEvent.isCancelled()) { -+ this.silentDeath = false; // Reset to default if event was cancelled -+ return; -+ } -+ // Paper end - Fire entity death event - this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause - this.gameEvent(GameEvent.ENTITY_DIE); - if (this.dragonFight != null) { diff --git a/patches/server/0854-Add-Listing-API-for-Player.patch b/patches/server/0854-Add-Listing-API-for-Player.patch new file mode 100644 index 0000000000..a411628340 --- /dev/null +++ b/patches/server/0854-Add-Listing-API-for-Player.patch @@ -0,0 +1,186 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Corey Shupe +Date: Wed, 11 Jan 2023 16:40:39 -0500 +Subject: [PATCH] Add Listing API for Player + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java +index 29b465fc1dc50e0e84ddb889c5303e80fe662874..4d67d98257b2cb9045d03c999cfd4ba2caf8453c 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java +@@ -37,6 +37,17 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet actions, List entries) { ++ this.actions = actions; ++ this.entries = entries; ++ } ++ ++ public ClientboundPlayerInfoUpdatePacket(EnumSet actions, ClientboundPlayerInfoUpdatePacket.Entry entry) { ++ this.actions = actions; ++ this.entries = List.of(entry); ++ } ++ // Paper end - Add Listing API for Player + + public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection players) { + EnumSet enumSet = EnumSet.of( +@@ -51,6 +62,28 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet players, ServerPlayer forPlayer) { ++ final EnumSet enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME); ++ final List entries = new java.util.ArrayList<>(players.size()); ++ final org.bukkit.craftbukkit.entity.CraftPlayer bukkitEntity = forPlayer.getBukkitEntity(); ++ for (final ServerPlayer player : players) { ++ entries.add(new ClientboundPlayerInfoUpdatePacket.Entry(player, bukkitEntity.isListed(player.getBukkitEntity()))); ++ } ++ return new ClientboundPlayerInfoUpdatePacket(enumSet, entries); ++ } ++ ++ public static ClientboundPlayerInfoUpdatePacket createSinglePlayerInitializing(ServerPlayer player, boolean listed) { ++ final EnumSet enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME); ++ final List entries = List.of(new Entry(player, listed)); ++ return new ClientboundPlayerInfoUpdatePacket(enumSet, entries); ++ } ++ ++ public static ClientboundPlayerInfoUpdatePacket updateListed(UUID playerInfoId, boolean listed) { ++ EnumSet enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED); ++ return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, listed)); ++ } ++ // Paper end - Add Listing API for Player + private ClientboundPlayerInfoUpdatePacket(RegistryFriendlyByteBuf buf) { + this.actions = buf.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class); + this.entries = buf.readList(buf2 -> { +@@ -161,10 +194,15 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join + for (int i = 0; i < this.players.size(); ++i) { + ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i); + + if (entityplayer1.getBukkitEntity().canSee(bukkitPlayer)) { ++ // Paper start - Add Listing API for Player ++ if (entityplayer1.getBukkitEntity().isListed(bukkitPlayer)) { ++ // Paper end - Add Listing API for Player + entityplayer1.connection.send(packet); ++ // Paper start - Add Listing API for Player ++ } else { ++ entityplayer1.connection.send(ClientboundPlayerInfoUpdatePacket.createSinglePlayerInitializing(player, false)); ++ } ++ // Paper end - Add Listing API for Player + } + + if (entityplayer1 == player || !bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { // Paper - Use single player info update packet on join; Don't include joining player +@@ -380,7 +388,7 @@ public abstract class PlayerList { + } + // Paper start - Use single player info update packet on join + if (!onlinePlayers.isEmpty()) { +- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers)); ++ player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, player)); // Paper - Add Listing API for Player + } + // Paper end - Use single player info update packet on join + player.sentListPacket = true; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 80877e62d0743891f38abeee5b5b04b4f3bc4010..1943cb7b691573d3f9755d21d4b5a4210c1cc329 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -206,6 +206,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + private final ConversationTracker conversationTracker = new ConversationTracker(); + private final Set channels = new HashSet(); + private final Map>> invertedVisibilityEntities = new HashMap<>(); ++ private final Set unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player + private static final WeakHashMap> pluginWeakReferences = new WeakHashMap<>(); + private int hash = 0; + private double health = 20; +@@ -2122,7 +2123,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + otherPlayer.setUUID(uuidOverride); + } + // Paper end +- this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(otherPlayer))); ++ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(otherPlayer), this.getHandle())); // Paper - Add Listing API for Player + if (original != null) otherPlayer.setUUID(original); // Paper - uuid override + } + +@@ -2226,6 +2227,41 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + return (entity != null) ? this.canSee(entity) : false; // If we can't find it, we can't see it + } + ++ // Paper start - Add Listing API for Player ++ @Override ++ public boolean isListed(Player other) { ++ return !this.unlistedEntities.contains(other.getUniqueId()); ++ } ++ ++ @Override ++ public boolean unlistPlayer(@NotNull Player other) { ++ Preconditions.checkNotNull(other, "hidden entity cannot be null"); ++ if (this.getHandle().connection == null) return false; ++ if (!this.canSee(other)) return false; ++ ++ if (unlistedEntities.add(other.getUniqueId())) { ++ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateListed(other.getUniqueId(), false)); ++ return true; ++ } else { ++ return false; ++ } ++ } ++ ++ @Override ++ public boolean listPlayer(@NotNull Player other) { ++ Preconditions.checkNotNull(other, "hidden entity cannot be null"); ++ if (this.getHandle().connection == null) return false; ++ if (!this.canSee(other)) throw new IllegalStateException("Player cannot see other player"); ++ ++ if (this.unlistedEntities.remove(other.getUniqueId())) { ++ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateListed(other.getUniqueId(), true)); ++ return true; ++ } else { ++ return false; ++ } ++ } ++ // Paper end - Add Listing API for Player ++ + @Override + public Map serialize() { + Map result = new LinkedHashMap(); diff --git a/patches/server/0854-Configurable-entity-tracking-range-by-Y-coordinate.patch b/patches/server/0854-Configurable-entity-tracking-range-by-Y-coordinate.patch deleted file mode 100644 index 75dd71166a..0000000000 --- a/patches/server/0854-Configurable-entity-tracking-range-by-Y-coordinate.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: ruViolence <78062896+ruViolence@users.noreply.github.com> -Date: Tue, 27 Jun 2023 15:38:18 +0800 -Subject: [PATCH] Configurable entity tracking range by Y coordinate - -Options to configure entity tracking by Y coordinate, also for each entity category. - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 7810df9c5045a78c2731ee416366da4f973e5d29..502d73830ed87e06529f194090a4ffb895b2623c 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1583,7 +1583,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - double d0 = (double) Math.min(this.getEffectiveRange(), i * 16); - double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; - double d2 = d0 * d0; -- boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); -+ // Paper start - Configurable entity tracking range by Y -+ boolean flag = d1 <= d2; -+ if (flag && level.paperConfig().entities.trackingRangeY.enabled) { -+ double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1); -+ if (rangeY != -1) { -+ double vec3d_dy = player.getY() - this.entity.getY(); -+ flag = vec3d_dy * vec3d_dy <= rangeY * rangeY; -+ } -+ } -+ flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); -+ // Paper end - Configurable entity tracking range by Y - - // CraftBukkit start - respect vanish API - if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { diff --git a/patches/server/0855-Add-Listing-API-for-Player.patch b/patches/server/0855-Add-Listing-API-for-Player.patch deleted file mode 100644 index 05d3d3e571..0000000000 --- a/patches/server/0855-Add-Listing-API-for-Player.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Corey Shupe -Date: Wed, 11 Jan 2023 16:40:39 -0500 -Subject: [PATCH] Add Listing API for Player - - -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -index 29b465fc1dc50e0e84ddb889c5303e80fe662874..4d67d98257b2cb9045d03c999cfd4ba2caf8453c 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -@@ -37,6 +37,17 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet actions, List entries) { -+ this.actions = actions; -+ this.entries = entries; -+ } -+ -+ public ClientboundPlayerInfoUpdatePacket(EnumSet actions, ClientboundPlayerInfoUpdatePacket.Entry entry) { -+ this.actions = actions; -+ this.entries = List.of(entry); -+ } -+ // Paper end - Add Listing API for Player - - public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection players) { - EnumSet enumSet = EnumSet.of( -@@ -51,6 +62,28 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet players, ServerPlayer forPlayer) { -+ final EnumSet enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME); -+ final List entries = new java.util.ArrayList<>(players.size()); -+ final org.bukkit.craftbukkit.entity.CraftPlayer bukkitEntity = forPlayer.getBukkitEntity(); -+ for (final ServerPlayer player : players) { -+ entries.add(new ClientboundPlayerInfoUpdatePacket.Entry(player, bukkitEntity.isListed(player.getBukkitEntity()))); -+ } -+ return new ClientboundPlayerInfoUpdatePacket(enumSet, entries); -+ } -+ -+ public static ClientboundPlayerInfoUpdatePacket createSinglePlayerInitializing(ServerPlayer player, boolean listed) { -+ final EnumSet enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME); -+ final List entries = List.of(new Entry(player, listed)); -+ return new ClientboundPlayerInfoUpdatePacket(enumSet, entries); -+ } -+ -+ public static ClientboundPlayerInfoUpdatePacket updateListed(UUID playerInfoId, boolean listed) { -+ EnumSet enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED); -+ return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, listed)); -+ } -+ // Paper end - Add Listing API for Player - private ClientboundPlayerInfoUpdatePacket(RegistryFriendlyByteBuf buf) { - this.actions = buf.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class); - this.entries = buf.readList(buf2 -> { -@@ -161,10 +194,15 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join - for (int i = 0; i < this.players.size(); ++i) { - ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i); - - if (entityplayer1.getBukkitEntity().canSee(bukkitPlayer)) { -+ // Paper start - Add Listing API for Player -+ if (entityplayer1.getBukkitEntity().isListed(bukkitPlayer)) { -+ // Paper end - Add Listing API for Player - entityplayer1.connection.send(packet); -+ // Paper start - Add Listing API for Player -+ } else { -+ entityplayer1.connection.send(ClientboundPlayerInfoUpdatePacket.createSinglePlayerInitializing(player, false)); -+ } -+ // Paper end - Add Listing API for Player - } - - if (entityplayer1 == player || !bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { // Paper - Use single player info update packet on join; Don't include joining player -@@ -381,7 +389,7 @@ public abstract class PlayerList { - } - // Paper start - Use single player info update packet on join - if (!onlinePlayers.isEmpty()) { -- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers)); -+ player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, player)); // Paper - Add Listing API for Player - } - // Paper end - Use single player info update packet on join - player.sentListPacket = true; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 80877e62d0743891f38abeee5b5b04b4f3bc4010..1943cb7b691573d3f9755d21d4b5a4210c1cc329 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -206,6 +206,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - private final ConversationTracker conversationTracker = new ConversationTracker(); - private final Set channels = new HashSet(); - private final Map>> invertedVisibilityEntities = new HashMap<>(); -+ private final Set unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player - private static final WeakHashMap> pluginWeakReferences = new WeakHashMap<>(); - private int hash = 0; - private double health = 20; -@@ -2122,7 +2123,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - otherPlayer.setUUID(uuidOverride); - } - // Paper end -- this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(otherPlayer))); -+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(otherPlayer), this.getHandle())); // Paper - Add Listing API for Player - if (original != null) otherPlayer.setUUID(original); // Paper - uuid override - } - -@@ -2226,6 +2227,41 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - return (entity != null) ? this.canSee(entity) : false; // If we can't find it, we can't see it - } - -+ // Paper start - Add Listing API for Player -+ @Override -+ public boolean isListed(Player other) { -+ return !this.unlistedEntities.contains(other.getUniqueId()); -+ } -+ -+ @Override -+ public boolean unlistPlayer(@NotNull Player other) { -+ Preconditions.checkNotNull(other, "hidden entity cannot be null"); -+ if (this.getHandle().connection == null) return false; -+ if (!this.canSee(other)) return false; -+ -+ if (unlistedEntities.add(other.getUniqueId())) { -+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateListed(other.getUniqueId(), false)); -+ return true; -+ } else { -+ return false; -+ } -+ } -+ -+ @Override -+ public boolean listPlayer(@NotNull Player other) { -+ Preconditions.checkNotNull(other, "hidden entity cannot be null"); -+ if (this.getHandle().connection == null) return false; -+ if (!this.canSee(other)) throw new IllegalStateException("Player cannot see other player"); -+ -+ if (this.unlistedEntities.remove(other.getUniqueId())) { -+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateListed(other.getUniqueId(), true)); -+ return true; -+ } else { -+ return false; -+ } -+ } -+ // Paper end - Add Listing API for Player -+ - @Override - public Map serialize() { - Map result = new LinkedHashMap(); diff --git a/patches/server/0855-Configurable-Region-Compression-Format.patch b/patches/server/0855-Configurable-Region-Compression-Format.patch new file mode 100644 index 0000000000..64a52a4ea2 --- /dev/null +++ b/patches/server/0855-Configurable-Region-Compression-Format.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Astralchroma +Date: Thu, 27 Oct 2022 22:19:31 +0100 +Subject: [PATCH] Configurable Region Compression Format + + +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +index f1237f6fd6414900ffbad0caee31aa83310eeef4..e858436bcf1b234d4bc6e6a117f5224d5c2d9f90 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +@@ -50,7 +50,7 @@ public class RegionFile implements AutoCloseable { + protected final RegionBitmap usedSectors; + + public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { +- this(storageKey, directory, path, RegionFileVersion.getSelected(), dsync); ++ this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format + } + + public RegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java +index cbd892598287c9358c1c2a3840c517462820b389..ef68b57ef1d8d7cb317c417569dd23a777fba4ad 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java +@@ -58,6 +58,15 @@ public class RegionFileVersion { + private final RegionFileVersion.StreamWrapper inputWrapper; + private final RegionFileVersion.StreamWrapper outputWrapper; + ++ // Paper start - Configurable region compression format ++ public static RegionFileVersion getCompressionFormat() { ++ return switch (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.compressionFormat) { ++ case GZIP -> VERSION_GZIP; ++ case ZLIB -> VERSION_DEFLATE; ++ case NONE -> VERSION_NONE; ++ }; ++ } ++ // Paper end - Configurable region compression format + private RegionFileVersion( + int id, + @Nullable String name, diff --git a/patches/server/0856-Add-BlockFace-to-BlockDamageEvent.patch b/patches/server/0856-Add-BlockFace-to-BlockDamageEvent.patch new file mode 100644 index 0000000000..2dcf331517 --- /dev/null +++ b/patches/server/0856-Add-BlockFace-to-BlockDamageEvent.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: aerulion +Date: Mon, 21 Aug 2023 04:36:07 +0200 +Subject: [PATCH] Add BlockFace to BlockDamageEvent + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 3bd4ab8161c29bb8df2ba496a4430393b6593476..0da6496c18341c01fc4551ead7e740a6037dcf31 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -259,7 +259,7 @@ public class ServerPlayerGameMode { + } + return; + } +- org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, pos, this.player.getInventory().getSelected(), f >= 1.0f); ++ org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, pos, direction, this.player.getInventory().getSelected(), f >= 1.0f); // Paper - Add BlockFace to BlockDamageEvent + + if (blockEvent.isCancelled()) { + // Let the client know the block still exists +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 449380c97dc332ecd43e308fcf110c9548930600..c5f9d9aeeb1fc61edb0e57cef51f5f6371861000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -660,13 +660,13 @@ public class CraftEventFactory { + /** + * BlockDamageEvent + */ +- public static BlockDamageEvent callBlockDamageEvent(ServerPlayer who, BlockPos pos, ItemStack itemstack, boolean instaBreak) { ++ public static BlockDamageEvent callBlockDamageEvent(ServerPlayer who, BlockPos pos, Direction direction, ItemStack itemstack, boolean instaBreak) { // Paper - Add BlockFace to BlockDamageEvent + Player player = who.getBukkitEntity(); + CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack); + + Block blockClicked = CraftBlock.at(who.level(), pos); + +- BlockDamageEvent event = new BlockDamageEvent(player, blockClicked, itemInHand, instaBreak); ++ BlockDamageEvent event = new BlockDamageEvent(player, blockClicked, CraftBlock.notchToBlockFace(direction), itemInHand, instaBreak); // Paper - Add BlockFace to BlockDamageEvent + player.getServer().getPluginManager().callEvent(event); + + return event; diff --git a/patches/server/0856-Configurable-Region-Compression-Format.patch b/patches/server/0856-Configurable-Region-Compression-Format.patch deleted file mode 100644 index 64a52a4ea2..0000000000 --- a/patches/server/0856-Configurable-Region-Compression-Format.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Astralchroma -Date: Thu, 27 Oct 2022 22:19:31 +0100 -Subject: [PATCH] Configurable Region Compression Format - - -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index f1237f6fd6414900ffbad0caee31aa83310eeef4..e858436bcf1b234d4bc6e6a117f5224d5c2d9f90 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -50,7 +50,7 @@ public class RegionFile implements AutoCloseable { - protected final RegionBitmap usedSectors; - - public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { -- this(storageKey, directory, path, RegionFileVersion.getSelected(), dsync); -+ this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format - } - - public RegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java -index cbd892598287c9358c1c2a3840c517462820b389..ef68b57ef1d8d7cb317c417569dd23a777fba4ad 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java -@@ -58,6 +58,15 @@ public class RegionFileVersion { - private final RegionFileVersion.StreamWrapper inputWrapper; - private final RegionFileVersion.StreamWrapper outputWrapper; - -+ // Paper start - Configurable region compression format -+ public static RegionFileVersion getCompressionFormat() { -+ return switch (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.compressionFormat) { -+ case GZIP -> VERSION_GZIP; -+ case ZLIB -> VERSION_DEFLATE; -+ case NONE -> VERSION_NONE; -+ }; -+ } -+ // Paper end - Configurable region compression format - private RegionFileVersion( - int id, - @Nullable String name, diff --git a/patches/server/0857-Add-BlockFace-to-BlockDamageEvent.patch b/patches/server/0857-Add-BlockFace-to-BlockDamageEvent.patch deleted file mode 100644 index 2dcf331517..0000000000 --- a/patches/server/0857-Add-BlockFace-to-BlockDamageEvent.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: aerulion -Date: Mon, 21 Aug 2023 04:36:07 +0200 -Subject: [PATCH] Add BlockFace to BlockDamageEvent - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 3bd4ab8161c29bb8df2ba496a4430393b6593476..0da6496c18341c01fc4551ead7e740a6037dcf31 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -259,7 +259,7 @@ public class ServerPlayerGameMode { - } - return; - } -- org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, pos, this.player.getInventory().getSelected(), f >= 1.0f); -+ org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, pos, direction, this.player.getInventory().getSelected(), f >= 1.0f); // Paper - Add BlockFace to BlockDamageEvent - - if (blockEvent.isCancelled()) { - // Let the client know the block still exists -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 449380c97dc332ecd43e308fcf110c9548930600..c5f9d9aeeb1fc61edb0e57cef51f5f6371861000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -660,13 +660,13 @@ public class CraftEventFactory { - /** - * BlockDamageEvent - */ -- public static BlockDamageEvent callBlockDamageEvent(ServerPlayer who, BlockPos pos, ItemStack itemstack, boolean instaBreak) { -+ public static BlockDamageEvent callBlockDamageEvent(ServerPlayer who, BlockPos pos, Direction direction, ItemStack itemstack, boolean instaBreak) { // Paper - Add BlockFace to BlockDamageEvent - Player player = who.getBukkitEntity(); - CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack); - - Block blockClicked = CraftBlock.at(who.level(), pos); - -- BlockDamageEvent event = new BlockDamageEvent(player, blockClicked, itemInHand, instaBreak); -+ BlockDamageEvent event = new BlockDamageEvent(player, blockClicked, CraftBlock.notchToBlockFace(direction), itemInHand, instaBreak); // Paper - Add BlockFace to BlockDamageEvent - player.getServer().getPluginManager().callEvent(event); - - return event; diff --git a/patches/server/0857-Fix-NPE-on-Boat-getStatus.patch b/patches/server/0857-Fix-NPE-on-Boat-getStatus.patch new file mode 100644 index 0000000000..19f832054d --- /dev/null +++ b/patches/server/0857-Fix-NPE-on-Boat-getStatus.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: LemonCaramel +Date: Mon, 10 Apr 2023 20:48:26 +0900 +Subject: [PATCH] Fix NPE on Boat getStatus + +Boat status is null until the entity is added to the world and the tick() method is called. + +== AT == +public net.minecraft.world.entity.vehicle.AbstractBoat getStatus()Lnet/minecraft/world/entity/vehicle/AbstractBoat$Status; + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java +index 5d51a49228eaee94f91cd04843e27c7918ca8796..ff82dc98478a8ac564bdbf4ec58da612e5f6c2ce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java +@@ -87,6 +87,17 @@ public abstract class CraftBoat extends CraftVehicle implements Boat { + + @Override + public Status getStatus() { ++ // Paper start - Fix NPE on Boat getStatus ++ final net.minecraft.world.entity.vehicle.AbstractBoat handle = this.getHandle(); ++ if (handle.status == null) { ++ if (handle.valid) { ++ // Don't actually set the status because it would skew the old status check in the next tick ++ return CraftBoat.boatStatusFromNms(handle.getStatus()); ++ } else { ++ return Status.NOT_IN_WORLD; ++ } ++ } ++ // Paper end - Fix NPE on Boat getStatus + return CraftBoat.boatStatusFromNms(this.getHandle().status); + } + diff --git a/patches/server/0858-Expand-Pose-API.patch b/patches/server/0858-Expand-Pose-API.patch new file mode 100644 index 0000000000..47312a8635 --- /dev/null +++ b/patches/server/0858-Expand-Pose-API.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 11 Jan 2023 20:59:01 +0200 +Subject: [PATCH] Expand Pose API + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 463dd4f91212318b51174c5d2f4d25ba95c25f50..eadea35bcb9c2a8d65789e09dbabe7cb4a126542 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -427,6 +427,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + @javax.annotation.Nullable + private UUID originWorld; + public boolean freezeLocked = false; // Paper - Freeze Tick Lock API ++ public boolean fixedPose = false; // Paper - Expand Pose API + + public void setOrigin(@javax.annotation.Nonnull Location location) { + this.origin = location.toVector(); +@@ -625,6 +626,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public void onRemoval(Entity.RemovalReason reason) {} + + public void setPose(net.minecraft.world.entity.Pose pose) { ++ if (this.fixedPose) return; // Paper - Expand Pose API + // CraftBukkit start + if (pose == this.getPose()) { + return; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index dd84f7d6874a799aa09349fe0a1bd6ebb4cea2dd..11a08ff211a9a32a825519ddb1736e02cf7f685e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -900,6 +900,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + public boolean isSneaking() { + return this.getHandle().isShiftKeyDown(); + } ++ ++ @Override ++ public void setPose(Pose pose, boolean fixed) { ++ Preconditions.checkNotNull(pose, "Pose cannot be null"); ++ final Entity handle = this.getHandle(); ++ handle.fixedPose = false; ++ handle.setPose(net.minecraft.world.entity.Pose.values()[pose.ordinal()]); ++ handle.fixedPose = fixed; ++ } ++ ++ @Override ++ public boolean hasFixedPose() { ++ return this.getHandle().fixedPose; ++ } + // Paper end + + @Override diff --git a/patches/server/0858-Fix-NPE-on-Boat-getStatus.patch b/patches/server/0858-Fix-NPE-on-Boat-getStatus.patch deleted file mode 100644 index 19f832054d..0000000000 --- a/patches/server/0858-Fix-NPE-on-Boat-getStatus.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LemonCaramel -Date: Mon, 10 Apr 2023 20:48:26 +0900 -Subject: [PATCH] Fix NPE on Boat getStatus - -Boat status is null until the entity is added to the world and the tick() method is called. - -== AT == -public net.minecraft.world.entity.vehicle.AbstractBoat getStatus()Lnet/minecraft/world/entity/vehicle/AbstractBoat$Status; - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java -index 5d51a49228eaee94f91cd04843e27c7918ca8796..ff82dc98478a8ac564bdbf4ec58da612e5f6c2ce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java -@@ -87,6 +87,17 @@ public abstract class CraftBoat extends CraftVehicle implements Boat { - - @Override - public Status getStatus() { -+ // Paper start - Fix NPE on Boat getStatus -+ final net.minecraft.world.entity.vehicle.AbstractBoat handle = this.getHandle(); -+ if (handle.status == null) { -+ if (handle.valid) { -+ // Don't actually set the status because it would skew the old status check in the next tick -+ return CraftBoat.boatStatusFromNms(handle.getStatus()); -+ } else { -+ return Status.NOT_IN_WORLD; -+ } -+ } -+ // Paper end - Fix NPE on Boat getStatus - return CraftBoat.boatStatusFromNms(this.getHandle().status); - } - diff --git a/patches/server/0859-Expand-Pose-API.patch b/patches/server/0859-Expand-Pose-API.patch deleted file mode 100644 index 47312a8635..0000000000 --- a/patches/server/0859-Expand-Pose-API.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SoSeDiK -Date: Wed, 11 Jan 2023 20:59:01 +0200 -Subject: [PATCH] Expand Pose API - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 463dd4f91212318b51174c5d2f4d25ba95c25f50..eadea35bcb9c2a8d65789e09dbabe7cb4a126542 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -427,6 +427,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - @javax.annotation.Nullable - private UUID originWorld; - public boolean freezeLocked = false; // Paper - Freeze Tick Lock API -+ public boolean fixedPose = false; // Paper - Expand Pose API - - public void setOrigin(@javax.annotation.Nonnull Location location) { - this.origin = location.toVector(); -@@ -625,6 +626,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public void onRemoval(Entity.RemovalReason reason) {} - - public void setPose(net.minecraft.world.entity.Pose pose) { -+ if (this.fixedPose) return; // Paper - Expand Pose API - // CraftBukkit start - if (pose == this.getPose()) { - return; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index dd84f7d6874a799aa09349fe0a1bd6ebb4cea2dd..11a08ff211a9a32a825519ddb1736e02cf7f685e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -900,6 +900,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - public boolean isSneaking() { - return this.getHandle().isShiftKeyDown(); - } -+ -+ @Override -+ public void setPose(Pose pose, boolean fixed) { -+ Preconditions.checkNotNull(pose, "Pose cannot be null"); -+ final Entity handle = this.getHandle(); -+ handle.fixedPose = false; -+ handle.setPose(net.minecraft.world.entity.Pose.values()[pose.ordinal()]); -+ handle.fixedPose = fixed; -+ } -+ -+ @Override -+ public boolean hasFixedPose() { -+ return this.getHandle().fixedPose; -+ } - // Paper end - - @Override diff --git a/patches/server/0859-More-DragonBattle-API.patch b/patches/server/0859-More-DragonBattle-API.patch new file mode 100644 index 0000000000..a752a4de81 --- /dev/null +++ b/patches/server/0859-More-DragonBattle-API.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 18 Dec 2022 13:40:05 -0800 +Subject: [PATCH] More DragonBattle API + +== AT == +public net.minecraft.world.level.dimension.end.EndDragonFight GATEWAY_COUNT +public net.minecraft.world.level.dimension.end.EndDragonFight gateways +public net.minecraft.world.level.dimension.end.EndDragonFight respawnCrystals +public net.minecraft.world.level.dimension.end.EndDragonFight spawnNewGateway(Lnet/minecraft/core/BlockPos;)V + +diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +index 39b1d6ee10d4a10ab4fb339621ca80f27d383324..8ec6b33126096fb9e1de5f41290097e004d7a455 100644 +--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java ++++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +@@ -442,6 +442,24 @@ public class EndDragonFight { + this.gateways.clear(); + } + ++ // Paper start - More DragonBattle API ++ public boolean spawnNewGatewayIfPossible() { ++ if (!this.gateways.isEmpty()) { ++ this.spawnNewGateway(); ++ return true; ++ } ++ return false; ++ } ++ ++ public List getSpikeCrystals() { ++ final List endCrystals = new java.util.ArrayList<>(); ++ for (final SpikeFeature.EndSpike spike : SpikeFeature.getSpikesForLevel(this.level)) { ++ endCrystals.addAll(this.level.getEntitiesOfClass(EndCrystal.class, spike.getTopBoundingBox())); ++ } ++ return endCrystals; ++ } ++ // Paper end - More DragonBattle API ++ + private void spawnNewGateway() { + if (!this.gateways.isEmpty()) { + int i = (Integer) this.gateways.remove(this.gateways.size() - 1); +diff --git a/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java b/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java +index dc7fdc120f4317ee1b7935ef226eddb0406aee6e..6bfabb38b51115beb2a65a165f235347838b6006 100644 +--- a/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java ++++ b/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java +@@ -137,4 +137,46 @@ public class CraftDragonBattle implements DragonBattle { + private DragonRespawnAnimation toNMSRespawnPhase(RespawnPhase phase) { + return (phase != RespawnPhase.NONE) ? DragonRespawnAnimation.values()[phase.ordinal()] : null; + } ++ // Paper start - More DragonBattle API ++ @Override ++ public int getGatewayCount() { ++ return EndDragonFight.GATEWAY_COUNT - this.handle.gateways.size(); ++ } ++ ++ @Override ++ public boolean spawnNewGateway() { ++ return this.handle.spawnNewGatewayIfPossible(); ++ } ++ ++ @Override ++ public void spawnNewGateway(final io.papermc.paper.math.Position position) { ++ this.handle.spawnNewGateway(io.papermc.paper.util.MCUtil.toBlockPos(position)); ++ } ++ ++ @Override ++ public java.util.List getRespawnCrystals() { ++ if (this.handle.respawnCrystals == null) { ++ return java.util.Collections.emptyList(); ++ } ++ ++ final java.util.List enderCrystals = new java.util.ArrayList<>(); ++ for (final net.minecraft.world.entity.boss.enderdragon.EndCrystal endCrystal : this.handle.respawnCrystals) { ++ if (!endCrystal.isRemoved() && endCrystal.isAlive() && endCrystal.valid) { ++ enderCrystals.add(((org.bukkit.entity.EnderCrystal) endCrystal.getBukkitEntity())); ++ } ++ } ++ return java.util.Collections.unmodifiableList(enderCrystals); ++ } ++ ++ @Override ++ public java.util.List getHealingCrystals() { ++ final java.util.List enderCrystals = new java.util.ArrayList<>(); ++ for (final net.minecraft.world.entity.boss.enderdragon.EndCrystal endCrystal : this.handle.getSpikeCrystals()) { ++ if (!endCrystal.isRemoved() && endCrystal.isAlive() && endCrystal.valid) { ++ enderCrystals.add(((org.bukkit.entity.EnderCrystal) endCrystal.getBukkitEntity())); ++ } ++ } ++ return java.util.Collections.unmodifiableList(enderCrystals); ++ } ++ // Paper end - More DragonBattle API + } diff --git a/patches/server/0860-Add-PlayerPickItemEvent.patch b/patches/server/0860-Add-PlayerPickItemEvent.patch new file mode 100644 index 0000000000..0290c1d950 --- /dev/null +++ b/patches/server/0860-Add-PlayerPickItemEvent.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com> +Date: Wed, 8 Sep 2021 21:34:01 +0200 +Subject: [PATCH] Add PlayerPickItemEvent + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 688d6e51bc8b844ba7648cf1aed1bdd9629c1675..b840f7aac9c830b8aa0aa133bf43f87dfc598b2c 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -947,7 +947,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.disconnect(Component.literal("Invalid hotbar selection (Hacking?)"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause + return; + } +- this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed ++ // Paper start - Add PlayerPickItemEvent ++ // this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed - moved down ++ Player bukkitPlayer = this.player.getBukkitEntity(); ++ int targetSlot = this.player.getInventory().getSuitableHotbarSlot(); ++ int sourceSlot = packet.getSlot(); ++ ++ io.papermc.paper.event.player.PlayerPickItemEvent event = new io.papermc.paper.event.player.PlayerPickItemEvent(bukkitPlayer, targetSlot, sourceSlot); ++ if (!event.callEvent()) return; ++ // Paper end - Add PlayerPickItemEvent ++ ++ this.player.getInventory().pickSlot(event.getSourceSlot(), event.getTargetSlot()); // Paper - Add PlayerPickItemEvent + // Paper end - validate pick item position + int i = this.player.getInventory().selected; + +diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java +index 8bdc2dd7e6b6824f4df5dce8bff5e87fa73d3d3a..aaff1592876ac4a967e4fd47e4b6619a17d57867 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Inventory.java ++++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java +@@ -170,7 +170,13 @@ public class Inventory implements Container, Nameable { + } + + public void pickSlot(int slot) { +- this.selected = this.getSuitableHotbarSlot(); ++ // Paper start - Add PlayerPickItemEvent ++ pickSlot(slot, this.getSuitableHotbarSlot()); ++ } ++ ++ public void pickSlot(int slot, int targetSlot) { ++ this.selected = targetSlot; ++ // Paper end - Add PlayerPickItemEvent + ItemStack itemstack = (ItemStack) this.items.get(this.selected); + + this.items.set(this.selected, (ItemStack) this.items.get(slot)); diff --git a/patches/server/0860-More-DragonBattle-API.patch b/patches/server/0860-More-DragonBattle-API.patch deleted file mode 100644 index a752a4de81..0000000000 --- a/patches/server/0860-More-DragonBattle-API.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 18 Dec 2022 13:40:05 -0800 -Subject: [PATCH] More DragonBattle API - -== AT == -public net.minecraft.world.level.dimension.end.EndDragonFight GATEWAY_COUNT -public net.minecraft.world.level.dimension.end.EndDragonFight gateways -public net.minecraft.world.level.dimension.end.EndDragonFight respawnCrystals -public net.minecraft.world.level.dimension.end.EndDragonFight spawnNewGateway(Lnet/minecraft/core/BlockPos;)V - -diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -index 39b1d6ee10d4a10ab4fb339621ca80f27d383324..8ec6b33126096fb9e1de5f41290097e004d7a455 100644 ---- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -@@ -442,6 +442,24 @@ public class EndDragonFight { - this.gateways.clear(); - } - -+ // Paper start - More DragonBattle API -+ public boolean spawnNewGatewayIfPossible() { -+ if (!this.gateways.isEmpty()) { -+ this.spawnNewGateway(); -+ return true; -+ } -+ return false; -+ } -+ -+ public List getSpikeCrystals() { -+ final List endCrystals = new java.util.ArrayList<>(); -+ for (final SpikeFeature.EndSpike spike : SpikeFeature.getSpikesForLevel(this.level)) { -+ endCrystals.addAll(this.level.getEntitiesOfClass(EndCrystal.class, spike.getTopBoundingBox())); -+ } -+ return endCrystals; -+ } -+ // Paper end - More DragonBattle API -+ - private void spawnNewGateway() { - if (!this.gateways.isEmpty()) { - int i = (Integer) this.gateways.remove(this.gateways.size() - 1); -diff --git a/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java b/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java -index dc7fdc120f4317ee1b7935ef226eddb0406aee6e..6bfabb38b51115beb2a65a165f235347838b6006 100644 ---- a/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java -+++ b/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java -@@ -137,4 +137,46 @@ public class CraftDragonBattle implements DragonBattle { - private DragonRespawnAnimation toNMSRespawnPhase(RespawnPhase phase) { - return (phase != RespawnPhase.NONE) ? DragonRespawnAnimation.values()[phase.ordinal()] : null; - } -+ // Paper start - More DragonBattle API -+ @Override -+ public int getGatewayCount() { -+ return EndDragonFight.GATEWAY_COUNT - this.handle.gateways.size(); -+ } -+ -+ @Override -+ public boolean spawnNewGateway() { -+ return this.handle.spawnNewGatewayIfPossible(); -+ } -+ -+ @Override -+ public void spawnNewGateway(final io.papermc.paper.math.Position position) { -+ this.handle.spawnNewGateway(io.papermc.paper.util.MCUtil.toBlockPos(position)); -+ } -+ -+ @Override -+ public java.util.List getRespawnCrystals() { -+ if (this.handle.respawnCrystals == null) { -+ return java.util.Collections.emptyList(); -+ } -+ -+ final java.util.List enderCrystals = new java.util.ArrayList<>(); -+ for (final net.minecraft.world.entity.boss.enderdragon.EndCrystal endCrystal : this.handle.respawnCrystals) { -+ if (!endCrystal.isRemoved() && endCrystal.isAlive() && endCrystal.valid) { -+ enderCrystals.add(((org.bukkit.entity.EnderCrystal) endCrystal.getBukkitEntity())); -+ } -+ } -+ return java.util.Collections.unmodifiableList(enderCrystals); -+ } -+ -+ @Override -+ public java.util.List getHealingCrystals() { -+ final java.util.List enderCrystals = new java.util.ArrayList<>(); -+ for (final net.minecraft.world.entity.boss.enderdragon.EndCrystal endCrystal : this.handle.getSpikeCrystals()) { -+ if (!endCrystal.isRemoved() && endCrystal.isAlive() && endCrystal.valid) { -+ enderCrystals.add(((org.bukkit.entity.EnderCrystal) endCrystal.getBukkitEntity())); -+ } -+ } -+ return java.util.Collections.unmodifiableList(enderCrystals); -+ } -+ // Paper end - More DragonBattle API - } diff --git a/patches/server/0861-Add-PlayerPickItemEvent.patch b/patches/server/0861-Add-PlayerPickItemEvent.patch deleted file mode 100644 index 8a28695a2b..0000000000 --- a/patches/server/0861-Add-PlayerPickItemEvent.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com> -Date: Wed, 8 Sep 2021 21:34:01 +0200 -Subject: [PATCH] Add PlayerPickItemEvent - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 293c42dd5e870986a2797840756bd7c4d6a34a5d..c50c3d11700aadd4c0e7114b4b6d5c5d15a33ac4 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -947,7 +947,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.disconnect(Component.literal("Invalid hotbar selection (Hacking?)"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause - return; - } -- this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed -+ // Paper start - Add PlayerPickItemEvent -+ // this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed - moved down -+ Player bukkitPlayer = this.player.getBukkitEntity(); -+ int targetSlot = this.player.getInventory().getSuitableHotbarSlot(); -+ int sourceSlot = packet.getSlot(); -+ -+ io.papermc.paper.event.player.PlayerPickItemEvent event = new io.papermc.paper.event.player.PlayerPickItemEvent(bukkitPlayer, targetSlot, sourceSlot); -+ if (!event.callEvent()) return; -+ // Paper end - Add PlayerPickItemEvent -+ -+ this.player.getInventory().pickSlot(event.getSourceSlot(), event.getTargetSlot()); // Paper - Add PlayerPickItemEvent - // Paper end - validate pick item position - int i = this.player.getInventory().selected; - -diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java -index 8bdc2dd7e6b6824f4df5dce8bff5e87fa73d3d3a..aaff1592876ac4a967e4fd47e4b6619a17d57867 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Inventory.java -+++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java -@@ -170,7 +170,13 @@ public class Inventory implements Container, Nameable { - } - - public void pickSlot(int slot) { -- this.selected = this.getSuitableHotbarSlot(); -+ // Paper start - Add PlayerPickItemEvent -+ pickSlot(slot, this.getSuitableHotbarSlot()); -+ } -+ -+ public void pickSlot(int slot, int targetSlot) { -+ this.selected = targetSlot; -+ // Paper end - Add PlayerPickItemEvent - ItemStack itemstack = (ItemStack) this.items.get(this.selected); - - this.items.set(this.selected, (ItemStack) this.items.get(slot)); diff --git a/patches/server/0861-Allow-trident-custom-damage.patch b/patches/server/0861-Allow-trident-custom-damage.patch new file mode 100644 index 0000000000..ee7ac1a043 --- /dev/null +++ b/patches/server/0861-Allow-trident-custom-damage.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Tue, 12 Jul 2022 18:01:14 +0200 +Subject: [PATCH] Allow trident custom damage + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java +index 248410547de380e3195bbdc8b7b39cff908a0c32..322733266fdca8ce43434a8ffea304c51794bcbb 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java +@@ -36,16 +36,19 @@ public class ThrownTrident extends AbstractArrow { + + public ThrownTrident(EntityType type, Level world) { + super(type, world); ++ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage + } + + public ThrownTrident(Level world, LivingEntity owner, ItemStack stack) { + super(EntityType.TRIDENT, owner, world, stack, (ItemStack) null); ++ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage + this.entityData.set(ThrownTrident.ID_LOYALTY, this.getLoyaltyFromItem(stack)); + this.entityData.set(ThrownTrident.ID_FOIL, stack.hasFoil()); + } + + public ThrownTrident(Level world, double x, double y, double z, ItemStack stack) { + super(EntityType.TRIDENT, x, y, z, world, stack, stack); ++ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage + this.entityData.set(ThrownTrident.ID_LOYALTY, this.getLoyaltyFromItem(stack)); + this.entityData.set(ThrownTrident.ID_FOIL, stack.hasFoil()); + } +@@ -136,7 +139,7 @@ public class ThrownTrident extends AbstractArrow { + @Override + protected void onHitEntity(EntityHitResult entityHitResult) { + Entity entity = entityHitResult.getEntity(); +- float f = 8.0F; ++ float f = (float) this.getBaseDamage(); // Paper - Allow trident custom damage + Entity entity1 = this.getOwner(); + DamageSource damagesource = this.damageSources().trident(this, (Entity) (entity1 == null ? this : entity1)); + Level world = this.level(); diff --git a/patches/server/0862-Allow-trident-custom-damage.patch b/patches/server/0862-Allow-trident-custom-damage.patch deleted file mode 100644 index ee7ac1a043..0000000000 --- a/patches/server/0862-Allow-trident-custom-damage.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Tue, 12 Jul 2022 18:01:14 +0200 -Subject: [PATCH] Allow trident custom damage - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -index 248410547de380e3195bbdc8b7b39cff908a0c32..322733266fdca8ce43434a8ffea304c51794bcbb 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -@@ -36,16 +36,19 @@ public class ThrownTrident extends AbstractArrow { - - public ThrownTrident(EntityType type, Level world) { - super(type, world); -+ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage - } - - public ThrownTrident(Level world, LivingEntity owner, ItemStack stack) { - super(EntityType.TRIDENT, owner, world, stack, (ItemStack) null); -+ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage - this.entityData.set(ThrownTrident.ID_LOYALTY, this.getLoyaltyFromItem(stack)); - this.entityData.set(ThrownTrident.ID_FOIL, stack.hasFoil()); - } - - public ThrownTrident(Level world, double x, double y, double z, ItemStack stack) { - super(EntityType.TRIDENT, x, y, z, world, stack, stack); -+ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage - this.entityData.set(ThrownTrident.ID_LOYALTY, this.getLoyaltyFromItem(stack)); - this.entityData.set(ThrownTrident.ID_FOIL, stack.hasFoil()); - } -@@ -136,7 +139,7 @@ public class ThrownTrident extends AbstractArrow { - @Override - protected void onHitEntity(EntityHitResult entityHitResult) { - Entity entity = entityHitResult.getEntity(); -- float f = 8.0F; -+ float f = (float) this.getBaseDamage(); // Paper - Allow trident custom damage - Entity entity1 = this.getOwner(); - DamageSource damagesource = this.damageSources().trident(this, (Entity) (entity1 == null ? this : entity1)); - Level world = this.level(); diff --git a/patches/server/0862-Expose-hand-in-BlockCanBuildEvent.patch b/patches/server/0862-Expose-hand-in-BlockCanBuildEvent.patch new file mode 100644 index 0000000000..f3ed54f3f9 --- /dev/null +++ b/patches/server/0862-Expose-hand-in-BlockCanBuildEvent.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: The456gamer +Date: Mon, 21 Aug 2023 14:13:42 +0100 +Subject: [PATCH] Expose hand in BlockCanBuildEvent + + +diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java +index d59120f0304823361cc4112f5583323945df4229..986b14a7b7c98641201ece649df09e4b8279a36c 100644 +--- a/src/main/java/net/minecraft/world/item/BlockItem.java ++++ b/src/main/java/net/minecraft/world/item/BlockItem.java +@@ -185,7 +185,7 @@ public class BlockItem extends Item { + boolean defaultReturn = (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && world.checkEntityCollision(state, entityhuman, voxelshapecollision, context.getClickedPos(), true); // Paper - Cancel hit for vanished players + org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null; + +- BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), defaultReturn); ++ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent + context.getLevel().getCraftServer().getPluginManager().callEvent(event); + + return event.isBuildable(); +diff --git a/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java b/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java +index 81915cec3ec372d1ff59160b96399b8c6e693eba..1451b25cedb7a8f01c046c8e1f8c6853aca42283 100644 +--- a/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java ++++ b/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java +@@ -59,7 +59,7 @@ public class StandingAndWallBlockItem extends BlockItem { + boolean defaultReturn = world.isUnobstructed(iblockdata1, blockposition, CollisionContext.empty()); + org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null; + +- BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(world, blockposition), player, CraftBlockData.fromData(iblockdata1), defaultReturn); ++ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(world, blockposition), player, CraftBlockData.fromData(iblockdata1), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent + context.getLevel().getCraftServer().getPluginManager().callEvent(event); + + return (event.isBuildable()) ? iblockdata1 : null; diff --git a/patches/server/0863-Expose-hand-in-BlockCanBuildEvent.patch b/patches/server/0863-Expose-hand-in-BlockCanBuildEvent.patch deleted file mode 100644 index f3ed54f3f9..0000000000 --- a/patches/server/0863-Expose-hand-in-BlockCanBuildEvent.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: The456gamer -Date: Mon, 21 Aug 2023 14:13:42 +0100 -Subject: [PATCH] Expose hand in BlockCanBuildEvent - - -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index d59120f0304823361cc4112f5583323945df4229..986b14a7b7c98641201ece649df09e4b8279a36c 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -185,7 +185,7 @@ public class BlockItem extends Item { - boolean defaultReturn = (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && world.checkEntityCollision(state, entityhuman, voxelshapecollision, context.getClickedPos(), true); // Paper - Cancel hit for vanished players - org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null; - -- BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), defaultReturn); -+ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent - context.getLevel().getCraftServer().getPluginManager().callEvent(event); - - return event.isBuildable(); -diff --git a/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java b/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java -index 81915cec3ec372d1ff59160b96399b8c6e693eba..1451b25cedb7a8f01c046c8e1f8c6853aca42283 100644 ---- a/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java -+++ b/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java -@@ -59,7 +59,7 @@ public class StandingAndWallBlockItem extends BlockItem { - boolean defaultReturn = world.isUnobstructed(iblockdata1, blockposition, CollisionContext.empty()); - org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null; - -- BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(world, blockposition), player, CraftBlockData.fromData(iblockdata1), defaultReturn); -+ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(world, blockposition), player, CraftBlockData.fromData(iblockdata1), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent - context.getLevel().getCraftServer().getPluginManager().callEvent(event); - - return (event.isBuildable()) ? iblockdata1 : null; diff --git a/patches/server/0863-Optimize-nearest-structure-border-iteration.patch b/patches/server/0863-Optimize-nearest-structure-border-iteration.patch new file mode 100644 index 0000000000..edd50774cc --- /dev/null +++ b/patches/server/0863-Optimize-nearest-structure-border-iteration.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martijn Muijsers +Date: Mon, 21 Aug 2023 21:05:09 +0200 +Subject: [PATCH] Optimize nearest structure border iteration + +Getting the nearest generated structure contains a nested set of loops that +iterates over all chunks at a specific chessboard distance. It does this by +iterating over the entire square of chunks within that distance, and checking +if the coordinates are at exactly the right distance to be on the border. + +This patch optimizes the iteration by only iterating over the border chunks. +This evaluated chunks are the same, and in the same order, as before, to +ensure that the returned found structure (which may for example be a buried +treasure that will be marked on a treasure map) is the same as in vanilla. + +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +index 31c5f54c90d6e35875f762747f8618e58e2eed91..582065b2d4e818c0edec36b2e9847f8ed3266b10 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -265,12 +265,15 @@ public abstract class ChunkGenerator { + int i1 = placement.spacing(); + + for (int j1 = -radius; j1 <= radius; ++j1) { +- boolean flag1 = j1 == -radius || j1 == radius; ++ // Paper start - Perf: iterate over border chunks instead of entire square chunk area ++ boolean flag1 = j1 == -radius || j1 == radius; final boolean onBorderAlongZAxis = flag1; // Paper - OBFHELPER + +- for (int k1 = -radius; k1 <= radius; ++k1) { +- boolean flag2 = k1 == -radius || k1 == radius; ++ for (int k1 = -radius; k1 <= radius; k1 += onBorderAlongZAxis ? 1 : radius * 2) { ++ // boolean flag2 = k1 == -radius || k1 == radius; + +- if (flag1 || flag2) { ++ // if (flag1 || flag2) { ++ if (true) { ++ // Paper end - Perf: iterate over border chunks instead of entire square chunk area + int l1 = centerChunkX + i1 * j1; + int i2 = centerChunkZ + i1 * k1; + ChunkPos chunkcoordintpair = placement.getPotentialStructureChunk(seed, l1, i2); diff --git a/patches/server/0864-Implement-OfflinePlayer-isConnected.patch b/patches/server/0864-Implement-OfflinePlayer-isConnected.patch new file mode 100644 index 0000000000..ebef6c5101 --- /dev/null +++ b/patches/server/0864-Implement-OfflinePlayer-isConnected.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aeltumn +Date: Thu, 24 Aug 2023 13:05:30 +0200 +Subject: [PATCH] Implement OfflinePlayer#isConnected + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +index 2c2c4db31a746b4eb853dc04c6b3e5631bbfa034..4f4e3ee18d586f61706504218cddc06a38ca5580 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +@@ -54,6 +54,13 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa + return this.getPlayer() != null; + } + ++ // Paper start ++ @Override ++ public boolean isConnected() { ++ return false; ++ } ++ // Paper end ++ + @Override + public String getName() { + Player player = this.getPlayer(); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 1943cb7b691573d3f9755d21d4b5a4210c1cc329..3b2d7837486424a2d1759c4ba5d1b1d492e9ec48 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -261,6 +261,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + return this.server.getPlayer(this.getUniqueId()) != null; + } + ++ // Paper start ++ @Override ++ public boolean isConnected() { ++ return !this.getHandle().hasDisconnected(); ++ } ++ // Paper end ++ + @Override + public InetSocketAddress getAddress() { + if (this.getHandle().connection.protocol() == null) return null; diff --git a/patches/server/0864-Optimize-nearest-structure-border-iteration.patch b/patches/server/0864-Optimize-nearest-structure-border-iteration.patch deleted file mode 100644 index edd50774cc..0000000000 --- a/patches/server/0864-Optimize-nearest-structure-border-iteration.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martijn Muijsers -Date: Mon, 21 Aug 2023 21:05:09 +0200 -Subject: [PATCH] Optimize nearest structure border iteration - -Getting the nearest generated structure contains a nested set of loops that -iterates over all chunks at a specific chessboard distance. It does this by -iterating over the entire square of chunks within that distance, and checking -if the coordinates are at exactly the right distance to be on the border. - -This patch optimizes the iteration by only iterating over the border chunks. -This evaluated chunks are the same, and in the same order, as before, to -ensure that the returned found structure (which may for example be a buried -treasure that will be marked on a treasure map) is the same as in vanilla. - -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index 31c5f54c90d6e35875f762747f8618e58e2eed91..582065b2d4e818c0edec36b2e9847f8ed3266b10 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -265,12 +265,15 @@ public abstract class ChunkGenerator { - int i1 = placement.spacing(); - - for (int j1 = -radius; j1 <= radius; ++j1) { -- boolean flag1 = j1 == -radius || j1 == radius; -+ // Paper start - Perf: iterate over border chunks instead of entire square chunk area -+ boolean flag1 = j1 == -radius || j1 == radius; final boolean onBorderAlongZAxis = flag1; // Paper - OBFHELPER - -- for (int k1 = -radius; k1 <= radius; ++k1) { -- boolean flag2 = k1 == -radius || k1 == radius; -+ for (int k1 = -radius; k1 <= radius; k1 += onBorderAlongZAxis ? 1 : radius * 2) { -+ // boolean flag2 = k1 == -radius || k1 == radius; - -- if (flag1 || flag2) { -+ // if (flag1 || flag2) { -+ if (true) { -+ // Paper end - Perf: iterate over border chunks instead of entire square chunk area - int l1 = centerChunkX + i1 * j1; - int i2 = centerChunkZ + i1 * k1; - ChunkPos chunkcoordintpair = placement.getPotentialStructureChunk(seed, l1, i2); diff --git a/patches/server/0865-Fix-slot-desync.patch b/patches/server/0865-Fix-slot-desync.patch new file mode 100644 index 0000000000..7c1808398c --- /dev/null +++ b/patches/server/0865-Fix-slot-desync.patch @@ -0,0 +1,129 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 23 Aug 2023 13:22:09 -0700 +Subject: [PATCH] Fix slot desync + +General patch fixing slot desyncs between the server and client that +result from cancelled events/paper introduced logic. + +Co-authored-by: Minecrell +Co-authored-by: Newwind + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index f05a9fd321a4af28e9771bbf39d73f80dd4160c9..90aa8e401e1d092a31ff21699409b8366629cdcc 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -460,6 +460,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + // Use method to resend items in hands in case of client desync, because the item use got cancelled. + // For example, when cancelling the leash event ++ @Deprecated // Paper - this shouldn't be used, use the regular sendAllDataToRemote call to resync all + public void resendItemInHands() { + this.containerMenu.findSlot(this.getInventory(), this.getInventory().selected).ifPresent(s -> { + this.containerSynchronizer.sendSlotChange(this.containerMenu, s, this.getMainHandItem()); +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index b840f7aac9c830b8aa0aa133bf43f87dfc598b2c..0cb0d2f863efb86bb589b30bae61ac57bda40fab 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2746,10 +2746,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // Refresh the current entity metadata + entity.refreshEntityData(ServerGamePacketListenerImpl.this.player); + // SPIGOT-7136 - Allays +- if (entity instanceof Allay) { ++ if (entity instanceof Allay || entity instanceof net.minecraft.world.entity.animal.horse.AbstractHorse) { // Paper - Fix horse armor desync + ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, ((LivingEntity) entity).getItemBySlot(slot).copy())).collect(Collectors.toList()))); +- ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); + } ++ ++ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); // Paper - fix slot desync - always refresh player inventory + } + + if (event.isCancelled()) { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index eadea35bcb9c2a8d65789e09dbabe7cb4a126542..c0539c8826a60cbe25855319cc174fb1520798c0 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2752,8 +2752,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (!this.level().isClientSide()) { + // CraftBukkit start - fire PlayerLeashEntityEvent + if (CraftEventFactory.callPlayerLeashEntityEvent(this, player, player, hand).isCancelled()) { +- ((ServerPlayer) player).resendItemInHands(); // SPIGOT-7615: Resend to fix client desync with used item ++ // ((ServerPlayer) player).resendItemInHands(); // SPIGOT-7615: Resend to fix client desync with used item // Paper - Fix inventory desync + ((ServerPlayer) player).connection.send(new ClientboundSetEntityLinkPacket(this, leashable.getLeashHolder())); ++ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.PASS; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java +index d99760f943846a1cfe5d0ec97313f453004feb98..3e00bbff266fc71b07014e7e047d77b7f809239f 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java +@@ -101,6 +101,7 @@ public class Cow extends Animal { + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand); + + if (event.isCancelled()) { ++ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.PASS; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +index 4c6dc427b90012b0945e073dd905dc7e8d1bec82..76aca47d8638d5c37c57d3a59fa7f8ceaa5a53b4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +@@ -238,6 +238,7 @@ public class Goat extends Animal { + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand); + + if (event.isCancelled()) { ++ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.PASS; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/item/ArmorStandItem.java b/src/main/java/net/minecraft/world/item/ArmorStandItem.java +index 15c7c2417db1661c77c35455b59a77b1d1055858..cb4baebe22eeab17aed67a5ecc506b932fe2230b 100644 +--- a/src/main/java/net/minecraft/world/item/ArmorStandItem.java ++++ b/src/main/java/net/minecraft/world/item/ArmorStandItem.java +@@ -55,6 +55,7 @@ public class ArmorStandItem extends Item { + entityarmorstand.moveTo(entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), f, 0.0F); + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityarmorstand).isCancelled()) { ++ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.FAIL; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java +index 986b14a7b7c98641201ece649df09e4b8279a36c..c816c935ecc74a811ffdffbe6ded73c06e92324a 100644 +--- a/src/main/java/net/minecraft/world/item/BlockItem.java ++++ b/src/main/java/net/minecraft/world/item/BlockItem.java +@@ -108,7 +108,7 @@ public class BlockItem extends Item { + if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { + blockstate.update(true, false); + +- if (this instanceof SolidBucketItem) { ++ if (true) { // Paper - if the event is called here, the inventory should be updated + ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 + } + return InteractionResult.FAIL; +diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java +index 5311e653dceb085fcebb8ac5090d84e97e573e62..48317c7436445a7acff9103bac1de558c42f31cc 100644 +--- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java ++++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java +@@ -49,6 +49,7 @@ public class EndCrystalItem extends Item { + entityendercrystal.setShowBottom(false); + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityendercrystal).isCancelled()) { ++ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.FAIL; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java +index 04eb25b05681a72968917b0b59c030d6629776fa..7153d9ed12276a0f2d8b8a17c79734aa25ed1fa5 100644 +--- a/src/main/java/net/minecraft/world/item/MinecartItem.java ++++ b/src/main/java/net/minecraft/world/item/MinecartItem.java +@@ -69,6 +69,7 @@ public class MinecartItem extends Item { + + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityminecartabstract).isCancelled()) { ++ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.FAIL; + } + // CraftBukkit end diff --git a/patches/server/0865-Implement-OfflinePlayer-isConnected.patch b/patches/server/0865-Implement-OfflinePlayer-isConnected.patch deleted file mode 100644 index ebef6c5101..0000000000 --- a/patches/server/0865-Implement-OfflinePlayer-isConnected.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aeltumn -Date: Thu, 24 Aug 2023 13:05:30 +0200 -Subject: [PATCH] Implement OfflinePlayer#isConnected - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -index 2c2c4db31a746b4eb853dc04c6b3e5631bbfa034..4f4e3ee18d586f61706504218cddc06a38ca5580 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -@@ -54,6 +54,13 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa - return this.getPlayer() != null; - } - -+ // Paper start -+ @Override -+ public boolean isConnected() { -+ return false; -+ } -+ // Paper end -+ - @Override - public String getName() { - Player player = this.getPlayer(); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 1943cb7b691573d3f9755d21d4b5a4210c1cc329..3b2d7837486424a2d1759c4ba5d1b1d492e9ec48 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -261,6 +261,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - return this.server.getPlayer(this.getUniqueId()) != null; - } - -+ // Paper start -+ @Override -+ public boolean isConnected() { -+ return !this.getHandle().hasDisconnected(); -+ } -+ // Paper end -+ - @Override - public InetSocketAddress getAddress() { - if (this.getHandle().connection.protocol() == null) return null; diff --git a/patches/server/0866-Add-titleOverride-to-InventoryOpenEvent.patch b/patches/server/0866-Add-titleOverride-to-InventoryOpenEvent.patch new file mode 100644 index 0000000000..1b98c1b4a0 --- /dev/null +++ b/patches/server/0866-Add-titleOverride-to-InventoryOpenEvent.patch @@ -0,0 +1,120 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 4 Mar 2022 12:45:03 -0800 +Subject: [PATCH] Add titleOverride to InventoryOpenEvent + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 90aa8e401e1d092a31ff21699409b8366629cdcc..419fcb4cd97cf10a2601e02024b999a51a0ff952 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1924,12 +1924,17 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.nextContainerCounter(); + AbstractContainerMenu container = factory.createMenu(this.containerCounter, this.getInventory(), this); + ++ Component title = null; // Paper - Add titleOverride to InventoryOpenEvent + // CraftBukkit start - Inventory open hook + if (container != null) { + container.setTitle(factory.getDisplayName()); + + boolean cancelled = false; +- container = CraftEventFactory.callInventoryOpenEvent(this, container, cancelled); ++ // Paper start - Add titleOverride to InventoryOpenEvent ++ final com.mojang.datafixers.util.Pair result = CraftEventFactory.callInventoryOpenEventWithTitle(this, container, cancelled); ++ container = result.getSecond(); ++ title = PaperAdventure.asVanilla(result.getFirst()); ++ // Paper end - Add titleOverride to InventoryOpenEvent + if (container == null && !cancelled) { // Let pre-cancelled events fall through + // SPIGOT-5263 - close chest if cancelled + if (factory instanceof Container) { +@@ -1951,7 +1956,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } else { + // CraftBukkit start + this.containerMenu = container; +- if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper - Prevent opening inventories when frozen ++ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), Objects.requireNonNullElseGet(title, container::getTitle))); // Paper - Add titleOverride to InventoryOpenEvent + // CraftBukkit end + this.initMenu(container); + return OptionalInt.of(this.containerCounter); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index 7dddf4dd090fcd9e86b147d7e4ddeaa99800713e..4312290ad970f71e1dc25b707ab312c597a481a9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -366,12 +366,16 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + Preconditions.checkArgument(windowType != null, "Unknown windowType"); + AbstractContainerMenu container = new CraftContainer(inventory, player, player.nextContainerCounter()); + +- container = CraftEventFactory.callInventoryOpenEvent(player, container); ++ // Paper start - Add titleOverride to InventoryOpenEvent ++ final com.mojang.datafixers.util.Pair result = CraftEventFactory.callInventoryOpenEventWithTitle(player, container); ++ container = result.getSecond(); ++ // Paper end - Add titleOverride to InventoryOpenEvent + if (container == null) return; + + //String title = container.getBukkitView().getTitle(); // Paper - comment + net.kyori.adventure.text.Component adventure$title = container.getBukkitView().title(); // Paper + if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(container.getBukkitView().getTitle()); // Paper ++ if (result.getFirst() != null) adventure$title = result.getFirst(); // Paper - Add titleOverride to InventoryOpenEvent + + //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment + if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen +@@ -448,7 +452,10 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + } + + // Trigger an INVENTORY_OPEN event +- container = CraftEventFactory.callInventoryOpenEvent(player, container); ++ // Paper start - Add titleOverride to InventoryOpenEvent ++ final com.mojang.datafixers.util.Pair result = CraftEventFactory.callInventoryOpenEventWithTitle(player, container); ++ container = result.getSecond(); ++ // Paper end - Add titleOverride to InventoryOpenEvent + if (container == null) { + return; + } +@@ -459,6 +466,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + //String title = inventory.getTitle(); // Paper - comment + net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper + if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(inventory.getTitle()); // Paper ++ if (result.getFirst() != null) adventure$title = result.getFirst(); // Paper - Add titleOverride to InventoryOpenEvent + //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment + if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen + player.containerMenu = container; +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index c5f9d9aeeb1fc61edb0e57cef51f5f6371861000..dbef230ae88ee1bfbc20ba53b534434c3ccac985 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1401,10 +1401,21 @@ public class CraftEventFactory { + } + + public static AbstractContainerMenu callInventoryOpenEvent(ServerPlayer player, AbstractContainerMenu container) { +- return CraftEventFactory.callInventoryOpenEvent(player, container, false); ++ // Paper start - Add titleOverride to InventoryOpenEvent ++ return callInventoryOpenEventWithTitle(player, container).getSecond(); ++ } ++ public static com.mojang.datafixers.util.Pair callInventoryOpenEventWithTitle(ServerPlayer player, AbstractContainerMenu container) { ++ return CraftEventFactory.callInventoryOpenEventWithTitle(player, container, false); ++ // Paper end - Add titleOverride to InventoryOpenEvent + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - use method that acknowledges title overrides + public static AbstractContainerMenu callInventoryOpenEvent(ServerPlayer player, AbstractContainerMenu container, boolean cancelled) { ++ // Paper start - Add titleOverride to InventoryOpenEvent ++ return callInventoryOpenEventWithTitle(player, container, cancelled).getSecond(); ++ } ++ public static com.mojang.datafixers.util.Pair callInventoryOpenEventWithTitle(ServerPlayer player, AbstractContainerMenu container, boolean cancelled) { ++ // Paper end - Add titleOverride to InventoryOpenEvent + if (player.containerMenu != player.inventoryMenu) { // fire INVENTORY_CLOSE if one already open + player.connection.handleContainerClose(new ServerboundContainerClosePacket(player.containerMenu.containerId), InventoryCloseEvent.Reason.OPEN_NEW); // Paper - Inventory close reason + } +@@ -1419,10 +1430,10 @@ public class CraftEventFactory { + + if (event.isCancelled()) { + container.transferTo(player.containerMenu, craftPlayer); +- return null; ++ return com.mojang.datafixers.util.Pair.of(null, null); // Paper - Add titleOverride to InventoryOpenEvent + } + +- return container; ++ return com.mojang.datafixers.util.Pair.of(event.titleOverride(), container); // Paper - Add titleOverride to InventoryOpenEvent + } + + public static ItemStack callPreCraftEvent(CraftingContainer matrix, Container resultInventory, ItemStack result, InventoryView lastCraftView, boolean isRepair) { diff --git a/patches/server/0866-Fix-slot-desync.patch b/patches/server/0866-Fix-slot-desync.patch deleted file mode 100644 index deb1575ede..0000000000 --- a/patches/server/0866-Fix-slot-desync.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 23 Aug 2023 13:22:09 -0700 -Subject: [PATCH] Fix slot desync - -General patch fixing slot desyncs between the server and client that -result from cancelled events/paper introduced logic. - -Co-authored-by: Minecrell -Co-authored-by: Newwind - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index f05a9fd321a4af28e9771bbf39d73f80dd4160c9..90aa8e401e1d092a31ff21699409b8366629cdcc 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -460,6 +460,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - // Use method to resend items in hands in case of client desync, because the item use got cancelled. - // For example, when cancelling the leash event -+ @Deprecated // Paper - this shouldn't be used, use the regular sendAllDataToRemote call to resync all - public void resendItemInHands() { - this.containerMenu.findSlot(this.getInventory(), this.getInventory().selected).ifPresent(s -> { - this.containerSynchronizer.sendSlotChange(this.containerMenu, s, this.getMainHandItem()); -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index c50c3d11700aadd4c0e7114b4b6d5c5d15a33ac4..af7696900171ea6b7941251046bfc10c1f4eb469 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2749,10 +2749,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // Refresh the current entity metadata - entity.refreshEntityData(ServerGamePacketListenerImpl.this.player); - // SPIGOT-7136 - Allays -- if (entity instanceof Allay) { -+ if (entity instanceof Allay || entity instanceof net.minecraft.world.entity.animal.horse.AbstractHorse) { // Paper - Fix horse armor desync - ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, ((LivingEntity) entity).getItemBySlot(slot).copy())).collect(Collectors.toList()))); -- ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); - } -+ -+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); // Paper - fix slot desync - always refresh player inventory - } - - if (event.isCancelled()) { -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index eadea35bcb9c2a8d65789e09dbabe7cb4a126542..c0539c8826a60cbe25855319cc174fb1520798c0 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2752,8 +2752,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (!this.level().isClientSide()) { - // CraftBukkit start - fire PlayerLeashEntityEvent - if (CraftEventFactory.callPlayerLeashEntityEvent(this, player, player, hand).isCancelled()) { -- ((ServerPlayer) player).resendItemInHands(); // SPIGOT-7615: Resend to fix client desync with used item -+ // ((ServerPlayer) player).resendItemInHands(); // SPIGOT-7615: Resend to fix client desync with used item // Paper - Fix inventory desync - ((ServerPlayer) player).connection.send(new ClientboundSetEntityLinkPacket(this, leashable.getLeashHolder())); -+ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync - return InteractionResult.PASS; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java -index d99760f943846a1cfe5d0ec97313f453004feb98..3e00bbff266fc71b07014e7e047d77b7f809239f 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java -@@ -101,6 +101,7 @@ public class Cow extends Animal { - PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand); - - if (event.isCancelled()) { -+ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync - return InteractionResult.PASS; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 4c6dc427b90012b0945e073dd905dc7e8d1bec82..76aca47d8638d5c37c57d3a59fa7f8ceaa5a53b4 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -238,6 +238,7 @@ public class Goat extends Animal { - PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand); - - if (event.isCancelled()) { -+ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync - return InteractionResult.PASS; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/item/ArmorStandItem.java b/src/main/java/net/minecraft/world/item/ArmorStandItem.java -index 15c7c2417db1661c77c35455b59a77b1d1055858..cb4baebe22eeab17aed67a5ecc506b932fe2230b 100644 ---- a/src/main/java/net/minecraft/world/item/ArmorStandItem.java -+++ b/src/main/java/net/minecraft/world/item/ArmorStandItem.java -@@ -55,6 +55,7 @@ public class ArmorStandItem extends Item { - entityarmorstand.moveTo(entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), f, 0.0F); - // CraftBukkit start - if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityarmorstand).isCancelled()) { -+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync - return InteractionResult.FAIL; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 986b14a7b7c98641201ece649df09e4b8279a36c..c816c935ecc74a811ffdffbe6ded73c06e92324a 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -108,7 +108,7 @@ public class BlockItem extends Item { - if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { - blockstate.update(true, false); - -- if (this instanceof SolidBucketItem) { -+ if (true) { // Paper - if the event is called here, the inventory should be updated - ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 - } - return InteractionResult.FAIL; -diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -index 5311e653dceb085fcebb8ac5090d84e97e573e62..48317c7436445a7acff9103bac1de558c42f31cc 100644 ---- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java -+++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -@@ -49,6 +49,7 @@ public class EndCrystalItem extends Item { - entityendercrystal.setShowBottom(false); - // CraftBukkit start - if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityendercrystal).isCancelled()) { -+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync - return InteractionResult.FAIL; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java -index 04eb25b05681a72968917b0b59c030d6629776fa..7153d9ed12276a0f2d8b8a17c79734aa25ed1fa5 100644 ---- a/src/main/java/net/minecraft/world/item/MinecartItem.java -+++ b/src/main/java/net/minecraft/world/item/MinecartItem.java -@@ -69,6 +69,7 @@ public class MinecartItem extends Item { - - // CraftBukkit start - if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityminecartabstract).isCancelled()) { -+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync - return InteractionResult.FAIL; - } - // CraftBukkit end diff --git a/patches/server/0867-Add-titleOverride-to-InventoryOpenEvent.patch b/patches/server/0867-Add-titleOverride-to-InventoryOpenEvent.patch deleted file mode 100644 index 1b98c1b4a0..0000000000 --- a/patches/server/0867-Add-titleOverride-to-InventoryOpenEvent.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 4 Mar 2022 12:45:03 -0800 -Subject: [PATCH] Add titleOverride to InventoryOpenEvent - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 90aa8e401e1d092a31ff21699409b8366629cdcc..419fcb4cd97cf10a2601e02024b999a51a0ff952 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1924,12 +1924,17 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.nextContainerCounter(); - AbstractContainerMenu container = factory.createMenu(this.containerCounter, this.getInventory(), this); - -+ Component title = null; // Paper - Add titleOverride to InventoryOpenEvent - // CraftBukkit start - Inventory open hook - if (container != null) { - container.setTitle(factory.getDisplayName()); - - boolean cancelled = false; -- container = CraftEventFactory.callInventoryOpenEvent(this, container, cancelled); -+ // Paper start - Add titleOverride to InventoryOpenEvent -+ final com.mojang.datafixers.util.Pair result = CraftEventFactory.callInventoryOpenEventWithTitle(this, container, cancelled); -+ container = result.getSecond(); -+ title = PaperAdventure.asVanilla(result.getFirst()); -+ // Paper end - Add titleOverride to InventoryOpenEvent - if (container == null && !cancelled) { // Let pre-cancelled events fall through - // SPIGOT-5263 - close chest if cancelled - if (factory instanceof Container) { -@@ -1951,7 +1956,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } else { - // CraftBukkit start - this.containerMenu = container; -- if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper - Prevent opening inventories when frozen -+ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), Objects.requireNonNullElseGet(title, container::getTitle))); // Paper - Add titleOverride to InventoryOpenEvent - // CraftBukkit end - this.initMenu(container); - return OptionalInt.of(this.containerCounter); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 7dddf4dd090fcd9e86b147d7e4ddeaa99800713e..4312290ad970f71e1dc25b707ab312c597a481a9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -366,12 +366,16 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - Preconditions.checkArgument(windowType != null, "Unknown windowType"); - AbstractContainerMenu container = new CraftContainer(inventory, player, player.nextContainerCounter()); - -- container = CraftEventFactory.callInventoryOpenEvent(player, container); -+ // Paper start - Add titleOverride to InventoryOpenEvent -+ final com.mojang.datafixers.util.Pair result = CraftEventFactory.callInventoryOpenEventWithTitle(player, container); -+ container = result.getSecond(); -+ // Paper end - Add titleOverride to InventoryOpenEvent - if (container == null) return; - - //String title = container.getBukkitView().getTitle(); // Paper - comment - net.kyori.adventure.text.Component adventure$title = container.getBukkitView().title(); // Paper - if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(container.getBukkitView().getTitle()); // Paper -+ if (result.getFirst() != null) adventure$title = result.getFirst(); // Paper - Add titleOverride to InventoryOpenEvent - - //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment - if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen -@@ -448,7 +452,10 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - } - - // Trigger an INVENTORY_OPEN event -- container = CraftEventFactory.callInventoryOpenEvent(player, container); -+ // Paper start - Add titleOverride to InventoryOpenEvent -+ final com.mojang.datafixers.util.Pair result = CraftEventFactory.callInventoryOpenEventWithTitle(player, container); -+ container = result.getSecond(); -+ // Paper end - Add titleOverride to InventoryOpenEvent - if (container == null) { - return; - } -@@ -459,6 +466,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - //String title = inventory.getTitle(); // Paper - comment - net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper - if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(inventory.getTitle()); // Paper -+ if (result.getFirst() != null) adventure$title = result.getFirst(); // Paper - Add titleOverride to InventoryOpenEvent - //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment - if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen - player.containerMenu = container; -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index c5f9d9aeeb1fc61edb0e57cef51f5f6371861000..dbef230ae88ee1bfbc20ba53b534434c3ccac985 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1401,10 +1401,21 @@ public class CraftEventFactory { - } - - public static AbstractContainerMenu callInventoryOpenEvent(ServerPlayer player, AbstractContainerMenu container) { -- return CraftEventFactory.callInventoryOpenEvent(player, container, false); -+ // Paper start - Add titleOverride to InventoryOpenEvent -+ return callInventoryOpenEventWithTitle(player, container).getSecond(); -+ } -+ public static com.mojang.datafixers.util.Pair callInventoryOpenEventWithTitle(ServerPlayer player, AbstractContainerMenu container) { -+ return CraftEventFactory.callInventoryOpenEventWithTitle(player, container, false); -+ // Paper end - Add titleOverride to InventoryOpenEvent - } - -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - use method that acknowledges title overrides - public static AbstractContainerMenu callInventoryOpenEvent(ServerPlayer player, AbstractContainerMenu container, boolean cancelled) { -+ // Paper start - Add titleOverride to InventoryOpenEvent -+ return callInventoryOpenEventWithTitle(player, container, cancelled).getSecond(); -+ } -+ public static com.mojang.datafixers.util.Pair callInventoryOpenEventWithTitle(ServerPlayer player, AbstractContainerMenu container, boolean cancelled) { -+ // Paper end - Add titleOverride to InventoryOpenEvent - if (player.containerMenu != player.inventoryMenu) { // fire INVENTORY_CLOSE if one already open - player.connection.handleContainerClose(new ServerboundContainerClosePacket(player.containerMenu.containerId), InventoryCloseEvent.Reason.OPEN_NEW); // Paper - Inventory close reason - } -@@ -1419,10 +1430,10 @@ public class CraftEventFactory { - - if (event.isCancelled()) { - container.transferTo(player.containerMenu, craftPlayer); -- return null; -+ return com.mojang.datafixers.util.Pair.of(null, null); // Paper - Add titleOverride to InventoryOpenEvent - } - -- return container; -+ return com.mojang.datafixers.util.Pair.of(event.titleOverride(), container); // Paper - Add titleOverride to InventoryOpenEvent - } - - public static ItemStack callPreCraftEvent(CraftingContainer matrix, Container resultInventory, ItemStack result, InventoryView lastCraftView, boolean isRepair) { diff --git a/patches/server/0867-Configure-sniffer-egg-hatch-time.patch b/patches/server/0867-Configure-sniffer-egg-hatch-time.patch new file mode 100644 index 0000000000..e39971b614 --- /dev/null +++ b/patches/server/0867-Configure-sniffer-egg-hatch-time.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Tue, 27 Jun 2023 13:26:06 +0200 +Subject: [PATCH] Configure sniffer egg hatch time + + +diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java +index c6b7cfd78bc0c4cb64eada507876c293541890f4..ec04fcc23c86d34a6dc1eaadda7f9d876f3d8ffe 100644 +--- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java +@@ -63,7 +63,7 @@ public class SnifferEggBlock extends Block { + + // Paper start - Call BlockFadeEvent + private void rescheduleTick(ServerLevel world, BlockPos pos) { +- int baseDelay = hatchBoost(world, pos) ? BOOSTED_HATCH_TIME_TICKS : REGULAR_HATCH_TIME_TICKS; ++ int baseDelay = hatchBoost(world, pos) ? world.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : world.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper - Configure sniffer egg hatch time + world.scheduleTick(pos, this, (baseDelay / 3) + world.random.nextInt(RANDOM_HATCH_OFFSET_TICKS)); + // reschedule to avoid being stuck here and behave like the other calls (see #onPlace) + } +@@ -105,7 +105,7 @@ public class SnifferEggBlock extends Block { + world.levelEvent(3009, pos, 0); + } + +- int i = bl ? 12000 : 24000; ++ int i = bl ? world.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : world.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper + int j = i / 3; + world.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(state)); + world.scheduleTick(pos, this, j + world.random.nextInt(300)); diff --git a/patches/server/0868-Configure-sniffer-egg-hatch-time.patch b/patches/server/0868-Configure-sniffer-egg-hatch-time.patch deleted file mode 100644 index e39971b614..0000000000 --- a/patches/server/0868-Configure-sniffer-egg-hatch-time.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Tue, 27 Jun 2023 13:26:06 +0200 -Subject: [PATCH] Configure sniffer egg hatch time - - -diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -index c6b7cfd78bc0c4cb64eada507876c293541890f4..ec04fcc23c86d34a6dc1eaadda7f9d876f3d8ffe 100644 ---- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java -@@ -63,7 +63,7 @@ public class SnifferEggBlock extends Block { - - // Paper start - Call BlockFadeEvent - private void rescheduleTick(ServerLevel world, BlockPos pos) { -- int baseDelay = hatchBoost(world, pos) ? BOOSTED_HATCH_TIME_TICKS : REGULAR_HATCH_TIME_TICKS; -+ int baseDelay = hatchBoost(world, pos) ? world.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : world.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper - Configure sniffer egg hatch time - world.scheduleTick(pos, this, (baseDelay / 3) + world.random.nextInt(RANDOM_HATCH_OFFSET_TICKS)); - // reschedule to avoid being stuck here and behave like the other calls (see #onPlace) - } -@@ -105,7 +105,7 @@ public class SnifferEggBlock extends Block { - world.levelEvent(3009, pos, 0); - } - -- int i = bl ? 12000 : 24000; -+ int i = bl ? world.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : world.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper - int j = i / 3; - world.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(state)); - world.scheduleTick(pos, this, j + world.random.nextInt(300)); diff --git a/patches/server/0868-Do-crystal-portal-proximity-check-before-entity-look.patch b/patches/server/0868-Do-crystal-portal-proximity-check-before-entity-look.patch new file mode 100644 index 0000000000..0ba2ce3d55 --- /dev/null +++ b/patches/server/0868-Do-crystal-portal-proximity-check-before-entity-look.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martijn Muijsers +Date: Tue, 15 Aug 2023 21:04:55 +0200 +Subject: [PATCH] Do crystal-portal proximity check before entity lookup + +This adds a very cheap distance check when an end crystal is placed. + +Attempting to respawn the dragon, which involves looking up the end crystal +entities near the portal, every time an end crystal is placed, can be slow on +some servers that have players placing end crystals as a style of combat. + +The very cheap distance check prevents running the entity lookup every time. + +diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java +index 48317c7436445a7acff9103bac1de558c42f31cc..b62db8c7c8c57e43869ee239ebf4b02f112355d9 100644 +--- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java ++++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java +@@ -30,7 +30,7 @@ public class EndCrystalItem extends Item { + if (!iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) { + return InteractionResult.FAIL; + } else { +- BlockPos blockposition1 = blockposition.above(); ++ BlockPos blockposition1 = blockposition.above(); final BlockPos aboveBlockPosition = blockposition1; // Paper - OBFHELPER + + if (!world.isEmptyBlock(blockposition1)) { + return InteractionResult.FAIL; +@@ -58,7 +58,7 @@ public class EndCrystalItem extends Item { + EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight(); + + if (enderdragonbattle != null) { +- enderdragonbattle.tryRespawn(); ++ enderdragonbattle.tryRespawn(aboveBlockPosition); // Paper - Perf: Do crystal-portal proximity check before entity lookup + } + } + +diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +index 8ec6b33126096fb9e1de5f41290097e004d7a455..b331c93c82c27f9456fec208a0c008c5bedfa8c4 100644 +--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java ++++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +@@ -563,6 +563,12 @@ public class EndDragonFight { + } + + public boolean tryRespawn() { // CraftBukkit - return boolean ++ // Paper start - Perf: Do crystal-portal proximity check before entity lookup ++ return this.tryRespawn(null); ++ } ++ ++ public boolean tryRespawn(@Nullable BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal ++ // Paper end - Perf: Do crystal-portal proximity check before entity lookup + if (this.dragonKilled && this.respawnStage == null) { + BlockPos blockposition = this.portalLocation; + +@@ -580,6 +586,22 @@ public class EndDragonFight { + blockposition = this.portalLocation; + } + ++ // Paper start - Perf: Do crystal-portal proximity check before entity lookup ++ if (placedEndCrystalPos != null) { ++ // The end crystal must be 0 or 1 higher than the portal origin ++ int dy = placedEndCrystalPos.getY() - blockposition.getY(); ++ if (dy != 0 && dy != 1) { ++ return false; ++ } ++ // The end crystal must be within a distance of 1 in one planar direction, and 3 in the other ++ int dx = placedEndCrystalPos.getX() - blockposition.getX(); ++ int dz = placedEndCrystalPos.getZ() - blockposition.getZ(); ++ if (!((dx >= -1 && dx <= 1 && dz >= -3 && dz <= 3) || (dx >= -3 && dx <= 3 && dz >= -1 && dz <= 1))) { ++ return false; ++ } ++ } ++ // Paper end - Perf: Do crystal-portal proximity check before entity lookup ++ + List list = Lists.newArrayList(); + BlockPos blockposition1 = blockposition.above(1); + Iterator iterator = Direction.Plane.HORIZONTAL.iterator(); diff --git a/patches/server/0869-Do-crystal-portal-proximity-check-before-entity-look.patch b/patches/server/0869-Do-crystal-portal-proximity-check-before-entity-look.patch deleted file mode 100644 index 0ba2ce3d55..0000000000 --- a/patches/server/0869-Do-crystal-portal-proximity-check-before-entity-look.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martijn Muijsers -Date: Tue, 15 Aug 2023 21:04:55 +0200 -Subject: [PATCH] Do crystal-portal proximity check before entity lookup - -This adds a very cheap distance check when an end crystal is placed. - -Attempting to respawn the dragon, which involves looking up the end crystal -entities near the portal, every time an end crystal is placed, can be slow on -some servers that have players placing end crystals as a style of combat. - -The very cheap distance check prevents running the entity lookup every time. - -diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -index 48317c7436445a7acff9103bac1de558c42f31cc..b62db8c7c8c57e43869ee239ebf4b02f112355d9 100644 ---- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java -+++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -@@ -30,7 +30,7 @@ public class EndCrystalItem extends Item { - if (!iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) { - return InteractionResult.FAIL; - } else { -- BlockPos blockposition1 = blockposition.above(); -+ BlockPos blockposition1 = blockposition.above(); final BlockPos aboveBlockPosition = blockposition1; // Paper - OBFHELPER - - if (!world.isEmptyBlock(blockposition1)) { - return InteractionResult.FAIL; -@@ -58,7 +58,7 @@ public class EndCrystalItem extends Item { - EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight(); - - if (enderdragonbattle != null) { -- enderdragonbattle.tryRespawn(); -+ enderdragonbattle.tryRespawn(aboveBlockPosition); // Paper - Perf: Do crystal-portal proximity check before entity lookup - } - } - -diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -index 8ec6b33126096fb9e1de5f41290097e004d7a455..b331c93c82c27f9456fec208a0c008c5bedfa8c4 100644 ---- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -@@ -563,6 +563,12 @@ public class EndDragonFight { - } - - public boolean tryRespawn() { // CraftBukkit - return boolean -+ // Paper start - Perf: Do crystal-portal proximity check before entity lookup -+ return this.tryRespawn(null); -+ } -+ -+ public boolean tryRespawn(@Nullable BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal -+ // Paper end - Perf: Do crystal-portal proximity check before entity lookup - if (this.dragonKilled && this.respawnStage == null) { - BlockPos blockposition = this.portalLocation; - -@@ -580,6 +586,22 @@ public class EndDragonFight { - blockposition = this.portalLocation; - } - -+ // Paper start - Perf: Do crystal-portal proximity check before entity lookup -+ if (placedEndCrystalPos != null) { -+ // The end crystal must be 0 or 1 higher than the portal origin -+ int dy = placedEndCrystalPos.getY() - blockposition.getY(); -+ if (dy != 0 && dy != 1) { -+ return false; -+ } -+ // The end crystal must be within a distance of 1 in one planar direction, and 3 in the other -+ int dx = placedEndCrystalPos.getX() - blockposition.getX(); -+ int dz = placedEndCrystalPos.getZ() - blockposition.getZ(); -+ if (!((dx >= -1 && dx <= 1 && dz >= -3 && dz <= 3) || (dx >= -3 && dx <= 3 && dz >= -1 && dz <= 1))) { -+ return false; -+ } -+ } -+ // Paper end - Perf: Do crystal-portal proximity check before entity lookup -+ - List list = Lists.newArrayList(); - BlockPos blockposition1 = blockposition.above(1); - Iterator iterator = Direction.Plane.HORIZONTAL.iterator(); diff --git a/patches/server/0869-Skip-POI-finding-if-stuck-in-vehicle.patch b/patches/server/0869-Skip-POI-finding-if-stuck-in-vehicle.patch new file mode 100644 index 0000000000..a4dcac44ac --- /dev/null +++ b/patches/server/0869-Skip-POI-finding-if-stuck-in-vehicle.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Thu, 18 Feb 2021 13:13:27 -0600 +Subject: [PATCH] Skip POI finding if stuck in vehicle + +Copyright (C) 2020 Technove LLC + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +index 21e50342598f7cd9efa1a39e70bd72d152d98812..e8aa27547e3fa1a42720889c7038d4fb0273e7b5 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +@@ -57,6 +57,7 @@ public class AcquirePoi { + return false; + } else { + mutableLong.setValue(time + 20L + (long)world.getRandom().nextInt(20)); ++ if (entity.getNavigation().isStuck()) mutableLong.add(200); // Paper - Perf: Wait an additional 10s to check again if they're stuck + PoiManager poiManager = world.getPoiManager(); + long2ObjectMap.long2ObjectEntrySet().removeIf(entry -> !entry.getValue().isStillValid(time)); + Predicate predicate2 = pos -> { diff --git a/patches/server/0870-Add-slot-sanity-checks-in-container-clicks.patch b/patches/server/0870-Add-slot-sanity-checks-in-container-clicks.patch new file mode 100644 index 0000000000..0925155fcf --- /dev/null +++ b/patches/server/0870-Add-slot-sanity-checks-in-container-clicks.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Mon, 11 Sep 2023 12:01:57 +1000 +Subject: [PATCH] Add slot sanity checks in container clicks + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 0cb0d2f863efb86bb589b30bae61ac57bda40fab..f92624ccd43f448abdee92c975d613cbcb3457c6 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3008,6 +3008,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + break; + case SWAP: + if ((packet.getButtonNum() >= 0 && packet.getButtonNum() < 9) || packet.getButtonNum() == 40) { ++ // Paper start - Add slot sanity checks to container clicks ++ if (packet.getSlotNum() < 0) { ++ action = InventoryAction.NOTHING; ++ break; ++ } ++ // Paper end - Add slot sanity checks to container clicks + click = (packet.getButtonNum() == 40) ? ClickType.SWAP_OFFHAND : ClickType.NUMBER_KEY; + Slot clickedSlot = this.player.containerMenu.getSlot(packet.getSlotNum()); + if (clickedSlot.mayPickup(this.player)) { +diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +index fc23e2dc42e907d5f8dc134a06102cc3e7fde515..22dc1569aabe69f139d9682ceb81311993706cb8 100644 +--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -460,6 +460,7 @@ public abstract class AbstractContainerMenu { + this.resetQuickCraft(); + } + } else if (this.quickcraftStatus == 1) { ++ if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks + slot = (Slot) this.slots.get(slotIndex); + itemstack = this.getCarried(); + if (AbstractContainerMenu.canItemQuickReplace(slot, itemstack, true) && slot.mayPlace(itemstack) && (this.quickcraftType == 2 || itemstack.getCount() > this.quickcraftSlots.size()) && this.canDragTo(slot)) { +@@ -634,6 +635,7 @@ public abstract class AbstractContainerMenu { + int j2; + + if (actionType == ClickType.SWAP && (button >= 0 && button < 9 || button == 40)) { ++ if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks + ItemStack itemstack4 = playerinventory.getItem(button); + + slot = (Slot) this.slots.get(slotIndex); diff --git a/patches/server/0870-Skip-POI-finding-if-stuck-in-vehicle.patch b/patches/server/0870-Skip-POI-finding-if-stuck-in-vehicle.patch deleted file mode 100644 index a4dcac44ac..0000000000 --- a/patches/server/0870-Skip-POI-finding-if-stuck-in-vehicle.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paul Sauve -Date: Thu, 18 Feb 2021 13:13:27 -0600 -Subject: [PATCH] Skip POI finding if stuck in vehicle - -Copyright (C) 2020 Technove LLC - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index 21e50342598f7cd9efa1a39e70bd72d152d98812..e8aa27547e3fa1a42720889c7038d4fb0273e7b5 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -57,6 +57,7 @@ public class AcquirePoi { - return false; - } else { - mutableLong.setValue(time + 20L + (long)world.getRandom().nextInt(20)); -+ if (entity.getNavigation().isStuck()) mutableLong.add(200); // Paper - Perf: Wait an additional 10s to check again if they're stuck - PoiManager poiManager = world.getPoiManager(); - long2ObjectMap.long2ObjectEntrySet().removeIf(entry -> !entry.getValue().isStillValid(time)); - Predicate predicate2 = pos -> { diff --git a/patches/server/0871-Add-slot-sanity-checks-in-container-clicks.patch b/patches/server/0871-Add-slot-sanity-checks-in-container-clicks.patch deleted file mode 100644 index 08f85bdb3b..0000000000 --- a/patches/server/0871-Add-slot-sanity-checks-in-container-clicks.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Mon, 11 Sep 2023 12:01:57 +1000 -Subject: [PATCH] Add slot sanity checks in container clicks - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index af7696900171ea6b7941251046bfc10c1f4eb469..836e6b705b201253f2b81d1ca0228b8a0266a1dd 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3011,6 +3011,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - break; - case SWAP: - if ((packet.getButtonNum() >= 0 && packet.getButtonNum() < 9) || packet.getButtonNum() == 40) { -+ // Paper start - Add slot sanity checks to container clicks -+ if (packet.getSlotNum() < 0) { -+ action = InventoryAction.NOTHING; -+ break; -+ } -+ // Paper end - Add slot sanity checks to container clicks - click = (packet.getButtonNum() == 40) ? ClickType.SWAP_OFFHAND : ClickType.NUMBER_KEY; - Slot clickedSlot = this.player.containerMenu.getSlot(packet.getSlotNum()); - if (clickedSlot.mayPickup(this.player)) { -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index fc23e2dc42e907d5f8dc134a06102cc3e7fde515..22dc1569aabe69f139d9682ceb81311993706cb8 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -460,6 +460,7 @@ public abstract class AbstractContainerMenu { - this.resetQuickCraft(); - } - } else if (this.quickcraftStatus == 1) { -+ if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks - slot = (Slot) this.slots.get(slotIndex); - itemstack = this.getCarried(); - if (AbstractContainerMenu.canItemQuickReplace(slot, itemstack, true) && slot.mayPlace(itemstack) && (this.quickcraftType == 2 || itemstack.getCount() > this.quickcraftSlots.size()) && this.canDragTo(slot)) { -@@ -634,6 +635,7 @@ public abstract class AbstractContainerMenu { - int j2; - - if (actionType == ClickType.SWAP && (button >= 0 && button < 9 || button == 40)) { -+ if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks - ItemStack itemstack4 = playerinventory.getItem(button); - - slot = (Slot) this.slots.get(slotIndex); diff --git a/patches/server/0871-Call-BlockRedstoneEvents-for-lecterns.patch b/patches/server/0871-Call-BlockRedstoneEvents-for-lecterns.patch new file mode 100644 index 0000000000..7726626d78 --- /dev/null +++ b/patches/server/0871-Call-BlockRedstoneEvents-for-lecterns.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Wed, 13 Sep 2023 05:46:10 +0200 +Subject: [PATCH] Call BlockRedstoneEvents for lecterns + + +diff --git a/src/main/java/net/minecraft/world/level/block/LecternBlock.java b/src/main/java/net/minecraft/world/level/block/LecternBlock.java +index 44d322d26187bd7528799069d0e08dbf571a57f3..3537795720be76483579fc50715914974c97c9c4 100644 +--- a/src/main/java/net/minecraft/world/level/block/LecternBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LecternBlock.java +@@ -180,6 +180,16 @@ public class LecternBlock extends BaseEntityBlock { + } + + private static void changePowered(Level world, BlockPos pos, BlockState state, boolean powered) { ++ // Paper start - call BlockRedstoneEvents for lecterns ++ final int currentRedstoneLevel = state.getValue(LecternBlock.POWERED) ? 15 : 0, targetRedstoneLevel = powered ? 15 : 0; ++ if (currentRedstoneLevel != targetRedstoneLevel) { ++ final org.bukkit.event.block.BlockRedstoneEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(world, pos, currentRedstoneLevel, targetRedstoneLevel); ++ ++ if (event.getNewCurrent() != targetRedstoneLevel) { ++ return; ++ } ++ } ++ // Paper end - call BlockRedstoneEvents for lecterns + world.setBlock(pos, (BlockState) state.setValue(LecternBlock.POWERED, powered), 3); + LecternBlock.updateBelow(world, pos, state); + } diff --git a/patches/server/0872-Allow-proper-checking-of-empty-item-stacks.patch b/patches/server/0872-Allow-proper-checking-of-empty-item-stacks.patch new file mode 100644 index 0000000000..85819379c1 --- /dev/null +++ b/patches/server/0872-Allow-proper-checking-of-empty-item-stacks.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aeltumn +Date: Mon, 28 Aug 2023 13:44:09 +0200 +Subject: [PATCH] Allow proper checking of empty item stacks + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 134db8c2dd72d0651fc889cc8931e7c971f62deb..30eba68435387daa3917fa2b3071892c350d9ddc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -45,12 +45,19 @@ public final class CraftItemStack extends ItemStack { + } + // Paper end - MC Utils + ++ // Paper start - override isEmpty to use vanilla's impl ++ @Override ++ public boolean isEmpty() { ++ return handle == null || handle.isEmpty(); ++ } ++ // Paper end - override isEmpty to use vanilla's impl ++ + public static net.minecraft.world.item.ItemStack asNMSCopy(ItemStack original) { + if (original instanceof CraftItemStack) { + CraftItemStack stack = (CraftItemStack) original; + return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy(); + } +- if (original == null || original.getType() == Material.AIR) { ++ if (original == null || original.isEmpty()) { // Paper - override isEmpty to use vanilla's impl; use isEmpty + return net.minecraft.world.item.ItemStack.EMPTY; + } + diff --git a/patches/server/0872-Call-BlockRedstoneEvents-for-lecterns.patch b/patches/server/0872-Call-BlockRedstoneEvents-for-lecterns.patch deleted file mode 100644 index 7726626d78..0000000000 --- a/patches/server/0872-Call-BlockRedstoneEvents-for-lecterns.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Wed, 13 Sep 2023 05:46:10 +0200 -Subject: [PATCH] Call BlockRedstoneEvents for lecterns - - -diff --git a/src/main/java/net/minecraft/world/level/block/LecternBlock.java b/src/main/java/net/minecraft/world/level/block/LecternBlock.java -index 44d322d26187bd7528799069d0e08dbf571a57f3..3537795720be76483579fc50715914974c97c9c4 100644 ---- a/src/main/java/net/minecraft/world/level/block/LecternBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LecternBlock.java -@@ -180,6 +180,16 @@ public class LecternBlock extends BaseEntityBlock { - } - - private static void changePowered(Level world, BlockPos pos, BlockState state, boolean powered) { -+ // Paper start - call BlockRedstoneEvents for lecterns -+ final int currentRedstoneLevel = state.getValue(LecternBlock.POWERED) ? 15 : 0, targetRedstoneLevel = powered ? 15 : 0; -+ if (currentRedstoneLevel != targetRedstoneLevel) { -+ final org.bukkit.event.block.BlockRedstoneEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(world, pos, currentRedstoneLevel, targetRedstoneLevel); -+ -+ if (event.getNewCurrent() != targetRedstoneLevel) { -+ return; -+ } -+ } -+ // Paper end - call BlockRedstoneEvents for lecterns - world.setBlock(pos, (BlockState) state.setValue(LecternBlock.POWERED, powered), 3); - LecternBlock.updateBelow(world, pos, state); - } diff --git a/patches/server/0873-Allow-proper-checking-of-empty-item-stacks.patch b/patches/server/0873-Allow-proper-checking-of-empty-item-stacks.patch deleted file mode 100644 index 85819379c1..0000000000 --- a/patches/server/0873-Allow-proper-checking-of-empty-item-stacks.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aeltumn -Date: Mon, 28 Aug 2023 13:44:09 +0200 -Subject: [PATCH] Allow proper checking of empty item stacks - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 134db8c2dd72d0651fc889cc8931e7c971f62deb..30eba68435387daa3917fa2b3071892c350d9ddc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -45,12 +45,19 @@ public final class CraftItemStack extends ItemStack { - } - // Paper end - MC Utils - -+ // Paper start - override isEmpty to use vanilla's impl -+ @Override -+ public boolean isEmpty() { -+ return handle == null || handle.isEmpty(); -+ } -+ // Paper end - override isEmpty to use vanilla's impl -+ - public static net.minecraft.world.item.ItemStack asNMSCopy(ItemStack original) { - if (original instanceof CraftItemStack) { - CraftItemStack stack = (CraftItemStack) original; - return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy(); - } -- if (original == null || original.getType() == Material.AIR) { -+ if (original == null || original.isEmpty()) { // Paper - override isEmpty to use vanilla's impl; use isEmpty - return net.minecraft.world.item.ItemStack.EMPTY; - } - diff --git a/patches/server/0873-Fix-silent-equipment-change-for-mobs.patch b/patches/server/0873-Fix-silent-equipment-change-for-mobs.patch new file mode 100644 index 0000000000..14b0a2dab0 --- /dev/null +++ b/patches/server/0873-Fix-silent-equipment-change-for-mobs.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Thu, 31 Aug 2023 17:32:48 +0200 +Subject: [PATCH] Fix silent equipment change for mobs + + +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index ac7a52e77fd2fcbe9f95709b95ba54f8c2a6514b..8a0e65ac8318a467996f48b423db1ac621359fbe 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -1100,19 +1100,26 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + + @Override + public void setItemSlot(EquipmentSlot slot, ItemStack stack) { ++ // Paper start - Fix silent equipment change ++ setItemSlot(slot, stack, false); ++ } ++ ++ @Override ++ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { ++ // Paper end - Fix silent equipment change + this.verifyEquippedItem(stack); + switch (slot.getType()) { + case HAND: +- this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change + break; + case HUMANOID_ARMOR: +- this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change + break; + case ANIMAL_ARMOR: + ItemStack itemstack1 = this.bodyArmorItem; + + this.bodyArmorItem = stack; +- this.onEquipItem(slot, itemstack1, stack); ++ this.onEquipItem(slot, itemstack1, stack, silent); // Paper - Fix silent equipment change + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +index 0cb179bc28cc863b09a079b37b957744f26f3e1d..32670a3cb4b54b66d655197e3fde834d2b2b6d34 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -258,8 +258,8 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + // Paper end - shouldBurnInDay API + + @Override +- public void setItemSlot(EquipmentSlot slot, ItemStack stack) { +- super.setItemSlot(slot, stack); ++ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { // Paper - Fix silent equipment change ++ super.setItemSlot(slot, stack, silent); // Paper - Fix silent equipment change + if (!this.level().isClientSide) { + this.reassessWeaponGoal(); + } +diff --git a/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java b/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..18e0ae815528f3b2f944febc01df48f346b3a4f6 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java +@@ -0,0 +1,52 @@ ++package io.papermc.paper.entity; ++ ++import io.github.classgraph.ClassGraph; ++import io.github.classgraph.ClassInfo; ++import io.github.classgraph.MethodInfo; ++import io.github.classgraph.MethodInfoList; ++import io.github.classgraph.MethodParameterInfo; ++import io.github.classgraph.ScanResult; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.stream.Stream; ++import org.bukkit.support.environment.Normal; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++import static org.junit.jupiter.api.Assertions.fail; ++ ++@Normal ++public class EntitySetItemSlotSilentOverrideTest { ++ ++ public static Stream parameters() { ++ final List classInfo = new ArrayList<>(); ++ try (ScanResult scanResult = new ClassGraph() ++ .enableClassInfo() ++ .enableMethodInfo() ++ .whitelistPackages("net.minecraft") ++ .scan() ++ ) { ++ for (final ClassInfo subclass : scanResult.getSubclasses("net.minecraft.world.entity.LivingEntity")) { ++ final MethodInfoList setItemSlot = subclass.getDeclaredMethodInfo("setItemSlot"); ++ if (!setItemSlot.isEmpty()) { ++ classInfo.add(subclass); ++ } ++ } ++ } ++ return classInfo.stream(); ++ } ++ ++ @ParameterizedTest ++ @MethodSource("parameters") ++ public void checkSetItemSlotSilentOverrides(ClassInfo overridesSetItemSlot) { ++ final MethodInfoList setItemSlot = overridesSetItemSlot.getDeclaredMethodInfo("setItemSlot"); ++ for (final MethodInfo methodInfo : setItemSlot) { ++ for (final MethodParameterInfo methodParameterInfo : methodInfo.getParameterInfo()) { ++ if ("boolean".equals(methodParameterInfo.getTypeDescriptor().toStringWithSimpleNames())) { ++ return; ++ } ++ } ++ } ++ fail(overridesSetItemSlot.getName() + " needs to override setItemSlot with the boolean silent parameter as well"); ++ } ++} diff --git a/patches/server/0874-Fix-silent-equipment-change-for-mobs.patch b/patches/server/0874-Fix-silent-equipment-change-for-mobs.patch deleted file mode 100644 index 14b0a2dab0..0000000000 --- a/patches/server/0874-Fix-silent-equipment-change-for-mobs.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Thu, 31 Aug 2023 17:32:48 +0200 -Subject: [PATCH] Fix silent equipment change for mobs - - -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index ac7a52e77fd2fcbe9f95709b95ba54f8c2a6514b..8a0e65ac8318a467996f48b423db1ac621359fbe 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1100,19 +1100,26 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - - @Override - public void setItemSlot(EquipmentSlot slot, ItemStack stack) { -+ // Paper start - Fix silent equipment change -+ setItemSlot(slot, stack, false); -+ } -+ -+ @Override -+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { -+ // Paper end - Fix silent equipment change - this.verifyEquippedItem(stack); - switch (slot.getType()) { - case HAND: -- this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack); -+ this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change - break; - case HUMANOID_ARMOR: -- this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack); -+ this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change - break; - case ANIMAL_ARMOR: - ItemStack itemstack1 = this.bodyArmorItem; - - this.bodyArmorItem = stack; -- this.onEquipItem(slot, itemstack1, stack); -+ this.onEquipItem(slot, itemstack1, stack, silent); // Paper - Fix silent equipment change - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -index 0cb179bc28cc863b09a079b37b957744f26f3e1d..32670a3cb4b54b66d655197e3fde834d2b2b6d34 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -258,8 +258,8 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - // Paper end - shouldBurnInDay API - - @Override -- public void setItemSlot(EquipmentSlot slot, ItemStack stack) { -- super.setItemSlot(slot, stack); -+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { // Paper - Fix silent equipment change -+ super.setItemSlot(slot, stack, silent); // Paper - Fix silent equipment change - if (!this.level().isClientSide) { - this.reassessWeaponGoal(); - } -diff --git a/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java b/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..18e0ae815528f3b2f944febc01df48f346b3a4f6 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java -@@ -0,0 +1,52 @@ -+package io.papermc.paper.entity; -+ -+import io.github.classgraph.ClassGraph; -+import io.github.classgraph.ClassInfo; -+import io.github.classgraph.MethodInfo; -+import io.github.classgraph.MethodInfoList; -+import io.github.classgraph.MethodParameterInfo; -+import io.github.classgraph.ScanResult; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.stream.Stream; -+import org.bukkit.support.environment.Normal; -+import org.junit.jupiter.params.ParameterizedTest; -+import org.junit.jupiter.params.provider.MethodSource; -+ -+import static org.junit.jupiter.api.Assertions.fail; -+ -+@Normal -+public class EntitySetItemSlotSilentOverrideTest { -+ -+ public static Stream parameters() { -+ final List classInfo = new ArrayList<>(); -+ try (ScanResult scanResult = new ClassGraph() -+ .enableClassInfo() -+ .enableMethodInfo() -+ .whitelistPackages("net.minecraft") -+ .scan() -+ ) { -+ for (final ClassInfo subclass : scanResult.getSubclasses("net.minecraft.world.entity.LivingEntity")) { -+ final MethodInfoList setItemSlot = subclass.getDeclaredMethodInfo("setItemSlot"); -+ if (!setItemSlot.isEmpty()) { -+ classInfo.add(subclass); -+ } -+ } -+ } -+ return classInfo.stream(); -+ } -+ -+ @ParameterizedTest -+ @MethodSource("parameters") -+ public void checkSetItemSlotSilentOverrides(ClassInfo overridesSetItemSlot) { -+ final MethodInfoList setItemSlot = overridesSetItemSlot.getDeclaredMethodInfo("setItemSlot"); -+ for (final MethodInfo methodInfo : setItemSlot) { -+ for (final MethodParameterInfo methodParameterInfo : methodInfo.getParameterInfo()) { -+ if ("boolean".equals(methodParameterInfo.getTypeDescriptor().toStringWithSimpleNames())) { -+ return; -+ } -+ } -+ } -+ fail(overridesSetItemSlot.getName() + " needs to override setItemSlot with the boolean silent parameter as well"); -+ } -+} diff --git a/patches/server/0874-Fix-spigot-s-Forced-Stats.patch b/patches/server/0874-Fix-spigot-s-Forced-Stats.patch new file mode 100644 index 0000000000..8e920d0d89 --- /dev/null +++ b/patches/server/0874-Fix-spigot-s-Forced-Stats.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: The456gamer +Date: Mon, 28 Aug 2023 01:32:39 +0100 +Subject: [PATCH] Fix spigot's Forced-Stats + +moves the loading after vanilla loading, so it overrides the values. +disables saving any forced stats, so it stays at the same value (without enabling disableStatSaving) +fixes stat initialization to not cause a NullPointerException + +diff --git a/src/main/java/net/minecraft/stats/ServerStatsCounter.java b/src/main/java/net/minecraft/stats/ServerStatsCounter.java +index ec437644adff6a6ec1e3fe2dd3a6354edafde1db..da7e1a69ecb4e6b3be2d8544ac406aa519bd196e 100644 +--- a/src/main/java/net/minecraft/stats/ServerStatsCounter.java ++++ b/src/main/java/net/minecraft/stats/ServerStatsCounter.java +@@ -48,13 +48,6 @@ public class ServerStatsCounter extends StatsCounter { + public ServerStatsCounter(MinecraftServer server, File file) { + this.server = server; + this.file = file; +- // Spigot start +- for ( Map.Entry entry : org.spigotmc.SpigotConfig.forcedStats.entrySet() ) +- { +- Stat wrapper = Stats.CUSTOM.get( entry.getKey() ); +- this.stats.put( wrapper, entry.getValue().intValue() ); +- } +- // Spigot end + if (file.isFile()) { + try { + this.parseLocal(server.getFixerUpper(), FileUtils.readFileToString(file)); +@@ -65,6 +58,18 @@ public class ServerStatsCounter extends StatsCounter { + } + } + ++ // Paper start - Moved after stat fetching for player state file ++ // Moves the loading after vanilla loading, so it overrides the values. ++ // Disables saving any forced stats, so it stays at the same value (without enabling disableStatSaving) ++ // Fixes stat initialization to not cause a NullPointerException ++ // Spigot start ++ for ( Map.Entry entry : org.spigotmc.SpigotConfig.forcedStats.entrySet() ) ++ { ++ Stat wrapper = Stats.CUSTOM.get(java.util.Objects.requireNonNull(BuiltInRegistries.CUSTOM_STAT.getValue(entry.getKey()))); // Paper - ensured by SpigotConfig#stats ++ this.stats.put( wrapper, entry.getValue().intValue() ); ++ } ++ // Spigot end ++ // Paper end - Moved after stat fetching for player state file + } + + public void save() { +@@ -80,6 +85,7 @@ public class ServerStatsCounter extends StatsCounter { + @Override + public void setValue(Player player, Stat stat, int value) { + if ( org.spigotmc.SpigotConfig.disableStatSaving ) return; // Spigot ++ if (stat.getType() == Stats.CUSTOM && stat.getValue() instanceof final ResourceLocation resourceLocation && org.spigotmc.SpigotConfig.forcedStats.get(resourceLocation) != null) return; // Paper - disable saving forced stats + super.setValue(player, stat, value); + this.dirty.add(stat); + } diff --git a/patches/server/0875-Add-missing-InventoryHolders-to-inventories.patch b/patches/server/0875-Add-missing-InventoryHolders-to-inventories.patch new file mode 100644 index 0000000000..d6bf23a4f8 --- /dev/null +++ b/patches/server/0875-Add-missing-InventoryHolders-to-inventories.patch @@ -0,0 +1,314 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 24 Jan 2022 00:09:02 -0800 +Subject: [PATCH] Add missing InventoryHolders to inventories + + +diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java +index db41ffbd24adccd78edf3368ba1f7a3ab9f6072c..5db5ba026462ca642dcee718af732f80fadabef5 100644 +--- a/src/main/java/net/minecraft/world/Container.java ++++ b/src/main/java/net/minecraft/world/Container.java +@@ -103,7 +103,7 @@ public interface Container extends Clearable { + + java.util.List getViewers(); + +- org.bukkit.inventory.InventoryHolder getOwner(); ++ org.bukkit.inventory.@org.jetbrains.annotations.Nullable InventoryHolder getOwner(); // Paper - annotation + + void setMaxStackSize(int size); + +diff --git a/src/main/java/net/minecraft/world/SimpleContainer.java b/src/main/java/net/minecraft/world/SimpleContainer.java +index b0963c534afe5be164701cb283f1849e32ae5a86..7ed52b887c4d766c23220a8809914d5d80f12ea4 100644 +--- a/src/main/java/net/minecraft/world/SimpleContainer.java ++++ b/src/main/java/net/minecraft/world/SimpleContainer.java +@@ -30,7 +30,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible { + // CraftBukkit start - add fields and methods + public List transaction = new java.util.ArrayList(); + private int maxStack = MAX_STACK; +- protected org.bukkit.inventory.InventoryHolder bukkitOwner; ++ protected @Nullable org.bukkit.inventory.InventoryHolder bukkitOwner; // Paper - annotation + + public List getContents() { + return this.items; +@@ -58,6 +58,11 @@ public class SimpleContainer implements Container, StackedContentsCompatible { + } + + public org.bukkit.inventory.InventoryHolder getOwner() { ++ // Paper start - Add missing InventoryHolders ++ if (this.bukkitOwner == null && this.bukkitOwnerCreator != null) { ++ this.bukkitOwner = this.bukkitOwnerCreator.get(); ++ } ++ // Paper end - Add missing InventoryHolders + return this.bukkitOwner; + } + +@@ -86,6 +91,13 @@ public class SimpleContainer implements Container, StackedContentsCompatible { + public SimpleContainer(int size) { + this(size, null); + } ++ // Paper start - Add missing InventoryHolders ++ private @Nullable java.util.function.Supplier bukkitOwnerCreator; ++ public SimpleContainer(java.util.function.Supplier bukkitOwnerCreator, int size) { ++ this(size); ++ this.bukkitOwnerCreator = bukkitOwnerCreator; ++ } ++ // Paper end - Add missing InventoryHolders + + public SimpleContainer(int i, org.bukkit.inventory.InventoryHolder owner) { + this.bukkitOwner = owner; +diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +index 22dc1569aabe69f139d9682ceb81311993706cb8..85caec29a705f216eff8a5ae11f250697891a05c 100644 +--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -1054,4 +1054,15 @@ public abstract class AbstractContainerMenu { + this.stateId = this.stateId + 1 & 32767; + return this.stateId; + } ++ ++ // Paper start - Add missing InventoryHolders ++ // The reason this is a supplier, is that the createHolder method uses the bukkit InventoryView#getTopInventory to get the inventory in question ++ // and that can't be obtained safely until the AbstractContainerMenu has been fully constructed. Using a supplier lazily ++ // initializes the InventoryHolder safely. ++ protected final Supplier createBlockHolder(final ContainerLevelAccess context) { ++ //noinspection ConstantValue ++ Preconditions.checkArgument(context != null, "context was null"); ++ return () -> context.createBlockHolder(this); ++ } ++ // Paper end - Add missing InventoryHolders + } +diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +index c0dfa04511110be366ee5b0bd75efc51afcce2e4..e0ee1c10960d24d2369d16f22431a8e02a5570aa 100644 +--- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +@@ -42,7 +42,7 @@ public class BeaconMenu extends AbstractContainerMenu { + public BeaconMenu(int syncId, Container inventory, ContainerData propertyDelegate, ContainerLevelAccess context) { + super(MenuType.BEACON, syncId); + this.player = (Inventory) inventory; // CraftBukkit - TODO: check this +- this.beacon = new SimpleContainer(1) { // CraftBukkit - decompile error ++ this.beacon = new SimpleContainer(this.createBlockHolder(context), 1) { // CraftBukkit - decompile error // Paper - Add missing InventoryHolders + @Override + public boolean canPlaceItem(int slot, ItemStack stack) { + return stack.is(ItemTags.BEACON_PAYMENT_ITEMS); +diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java +index 8b72d1fd551dcb113f4137aee441a9531c00288a..b3a16b024e46ee8203b225ee429a5c973eab12c6 100644 +--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java +@@ -54,7 +54,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { + + public CartographyTableMenu(int syncId, Inventory inventory, final ContainerLevelAccess context) { + super(MenuType.CARTOGRAPHY_TABLE, syncId); +- this.container = new SimpleContainer(2) { ++ this.container = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { + CartographyTableMenu.this.slotsChanged(this); +@@ -68,7 +68,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { + } + // CraftBukkit end + }; +- this.resultContainer = new ResultContainer() { ++ this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { + CartographyTableMenu.this.slotsChanged(this); +diff --git a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java +index 85e336637db8643fc5aca1dba724c9b341cbf46f..12b466ccb7c36021cf807c4f3fd2bcb037943abc 100644 +--- a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java ++++ b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java +@@ -21,6 +21,18 @@ public interface ContainerLevelAccess { + return new org.bukkit.Location(this.getWorld().getWorld(), this.getPosition().getX(), this.getPosition().getY(), this.getPosition().getZ()); + } + // CraftBukkit end ++ // Paper start - Add missing InventoryHolders ++ default boolean isBlock() { ++ return false; ++ } ++ ++ default org.bukkit.inventory.@org.jetbrains.annotations.Nullable BlockInventoryHolder createBlockHolder(AbstractContainerMenu menu) { ++ if (!this.isBlock()) { ++ return null; ++ } ++ return new org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder(this, menu.getBukkitView().getTopInventory()); ++ } ++ // Paper end - Add missing InventoryHolders + + ContainerLevelAccess NULL = new ContainerLevelAccess() { + @Override +@@ -48,6 +60,12 @@ public interface ContainerLevelAccess { + return pos; + } + // CraftBukkit end ++ // Paper start - Add missing InventoryHolders ++ @Override ++ public boolean isBlock() { ++ return true; ++ } ++ // Paper end - Add missing InventoryHolders + + @Override + public Optional evaluate(BiFunction getter) { +diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +index 2642d8ddc79ad97675f958c89ef03da39903f359..36496144dd6fa87163b692034570eba70c83678c 100644 +--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +@@ -63,7 +63,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { + + public EnchantmentMenu(int syncId, Inventory playerInventory, ContainerLevelAccess context) { + super(MenuType.ENCHANTMENT, syncId); +- this.enchantSlots = new SimpleContainer(2) { ++ this.enchantSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { + super.setChanged(); +diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java +index 8e58dbb4b110338dfe8add26697d0b1c9ec5fa9c..3b303d41b9facfb2892ff8402ee0de4608db7318 100644 +--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java +@@ -60,8 +60,8 @@ public class GrindstoneMenu extends AbstractContainerMenu { + + public GrindstoneMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) { + super(MenuType.GRINDSTONE, syncId); +- this.resultSlots = new ResultContainer(); +- this.repairSlots = new SimpleContainer(2) { ++ this.resultSlots = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders ++ this.repairSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { + super.setChanged(); +diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java +index 4734dd90f2a66e1ac7a64b35ecd62a630108cf07..a5d53a656513ae81cc3f9fc506caf6adaba62a8e 100644 +--- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java +@@ -17,12 +17,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { + protected final ContainerLevelAccess access; + protected final Player player; + protected final Container inputSlots; +- protected final ResultContainer resultSlots = new ResultContainer() { +- @Override +- public void setChanged() { +- ItemCombinerMenu.this.slotsChanged(this); +- } +- }; ++ protected final ResultContainer resultSlots; // Paper - Add missing InventoryHolders; delay field init + private final int resultSlotIndex; + + protected boolean mayPickup(Player player, boolean present) { +@@ -36,6 +31,14 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { + public ItemCombinerMenu(@Nullable MenuType type, int syncId, Inventory playerInventory, ContainerLevelAccess context, ItemCombinerMenuSlotDefinition forgingSlotsManager) { + super(type, syncId); + this.access = context; ++ // Paper start - Add missing InventoryHolders; delay field init ++ this.resultSlots = new ResultContainer(this.createBlockHolder(this.access)) { ++ @Override ++ public void setChanged() { ++ ItemCombinerMenu.this.slotsChanged(this); ++ } ++ }; ++ // Paper end - Add missing InventoryHolders; delay field init + this.player = playerInventory.player; + this.inputSlots = this.createContainer(forgingSlotsManager.getNumOfInputSlots()); + this.resultSlotIndex = forgingSlotsManager.getResultSlotIndex(); +@@ -82,7 +85,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { + public abstract void createResult(); + + private SimpleContainer createContainer(int size) { +- return new SimpleContainer(size) { ++ return new SimpleContainer(this.createBlockHolder(this.access), size) { + @Override + public void setChanged() { + super.setChanged(); +diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java +index 1b7cf165ab0818792870f43719a6324b282bb57a..98519dd3bccca516acdedc69a59189b1106fb75b 100644 +--- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java +@@ -73,7 +73,7 @@ public class LoomMenu extends AbstractContainerMenu { + this.selectablePatterns = List.of(); + this.slotUpdateListener = () -> { + }; +- this.inputContainer = new SimpleContainer(3) { ++ this.inputContainer = new SimpleContainer(this.createBlockHolder(context), 3) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { + super.setChanged(); +@@ -88,7 +88,7 @@ public class LoomMenu extends AbstractContainerMenu { + } + // CraftBukkit end + }; +- this.outputContainer = new SimpleContainer(1) { ++ this.outputContainer = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { + super.setChanged(); +diff --git a/src/main/java/net/minecraft/world/inventory/ResultContainer.java b/src/main/java/net/minecraft/world/inventory/ResultContainer.java +index d4592218d761eb38402e3d95c642e80a708cb333..4c4266a85c38e41e6c7e6144a68624f4daa50c54 100644 +--- a/src/main/java/net/minecraft/world/inventory/ResultContainer.java ++++ b/src/main/java/net/minecraft/world/inventory/ResultContainer.java +@@ -29,7 +29,12 @@ public class ResultContainer implements Container, RecipeCraftingHolder { + } + + public org.bukkit.inventory.InventoryHolder getOwner() { +- return null; // Result slots don't get an owner ++ // Paper start - Add missing InventoryHolders ++ if (this.holder == null && this.holderCreator != null) { ++ this.holder = this.holderCreator.get(); ++ } ++ return this.holder; // Result slots don't get an owner ++ // Paper end - Add missing InventoryHolders + } + + // Don't need a transaction; the InventoryCrafting keeps track of it for us +@@ -53,6 +58,14 @@ public class ResultContainer implements Container, RecipeCraftingHolder { + return null; + } + // CraftBukkit end ++ // Paper start - Add missing InventoryHolders ++ private @Nullable java.util.function.Supplier holderCreator; ++ private @Nullable org.bukkit.inventory.InventoryHolder holder; ++ public ResultContainer(java.util.function.Supplier holderCreator) { ++ this(); ++ this.holderCreator = holderCreator; ++ } ++ // Paper end - Add missing InventoryHolders + + public ResultContainer() { + this.itemStacks = NonNullList.withSize(1, ItemStack.EMPTY); +diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java +index a93870952e2ef674028b8a20aa52a685c743e7ea..ca65965757e6f12abc972250a04817c7547bb0bd 100644 +--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java +@@ -69,7 +69,7 @@ public class StonecutterMenu extends AbstractContainerMenu { + this.input = ItemStack.EMPTY; + this.slotUpdateListener = () -> { + }; +- this.container = new SimpleContainer(1) { ++ this.container = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { + super.setChanged(); +@@ -84,7 +84,7 @@ public class StonecutterMenu extends AbstractContainerMenu { + } + // CraftBukkit end + }; +- this.resultContainer = new ResultContainer(); ++ this.resultContainer = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders + this.access = context; + this.level = playerInventory.player.level(); + this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33)); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java +index 7ae484b0fa5bf5494c6ead15f7f1c0fa840ae270..7129eb5f5cea39992b4c690cb421004004a952ea 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java +@@ -17,6 +17,13 @@ public class CraftBlockInventoryHolder implements BlockInventoryHolder { + this.block = CraftBlock.at(world, pos); + this.inventory = new CraftInventory(inv); + } ++ // Paper start - Add missing InventoryHolders ++ public CraftBlockInventoryHolder(net.minecraft.world.inventory.ContainerLevelAccess levelAccess, Inventory inventory) { ++ com.google.common.base.Preconditions.checkArgument(levelAccess.isBlock()); ++ this.block = CraftBlock.at(levelAccess.getWorld(), levelAccess.getPosition()); ++ this.inventory = inventory; ++ } ++ // Paper end - Add missing InventoryHolders + + @Override + public Block getBlock() { diff --git a/patches/server/0875-Fix-spigot-s-Forced-Stats.patch b/patches/server/0875-Fix-spigot-s-Forced-Stats.patch deleted file mode 100644 index 8e920d0d89..0000000000 --- a/patches/server/0875-Fix-spigot-s-Forced-Stats.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: The456gamer -Date: Mon, 28 Aug 2023 01:32:39 +0100 -Subject: [PATCH] Fix spigot's Forced-Stats - -moves the loading after vanilla loading, so it overrides the values. -disables saving any forced stats, so it stays at the same value (without enabling disableStatSaving) -fixes stat initialization to not cause a NullPointerException - -diff --git a/src/main/java/net/minecraft/stats/ServerStatsCounter.java b/src/main/java/net/minecraft/stats/ServerStatsCounter.java -index ec437644adff6a6ec1e3fe2dd3a6354edafde1db..da7e1a69ecb4e6b3be2d8544ac406aa519bd196e 100644 ---- a/src/main/java/net/minecraft/stats/ServerStatsCounter.java -+++ b/src/main/java/net/minecraft/stats/ServerStatsCounter.java -@@ -48,13 +48,6 @@ public class ServerStatsCounter extends StatsCounter { - public ServerStatsCounter(MinecraftServer server, File file) { - this.server = server; - this.file = file; -- // Spigot start -- for ( Map.Entry entry : org.spigotmc.SpigotConfig.forcedStats.entrySet() ) -- { -- Stat wrapper = Stats.CUSTOM.get( entry.getKey() ); -- this.stats.put( wrapper, entry.getValue().intValue() ); -- } -- // Spigot end - if (file.isFile()) { - try { - this.parseLocal(server.getFixerUpper(), FileUtils.readFileToString(file)); -@@ -65,6 +58,18 @@ public class ServerStatsCounter extends StatsCounter { - } - } - -+ // Paper start - Moved after stat fetching for player state file -+ // Moves the loading after vanilla loading, so it overrides the values. -+ // Disables saving any forced stats, so it stays at the same value (without enabling disableStatSaving) -+ // Fixes stat initialization to not cause a NullPointerException -+ // Spigot start -+ for ( Map.Entry entry : org.spigotmc.SpigotConfig.forcedStats.entrySet() ) -+ { -+ Stat wrapper = Stats.CUSTOM.get(java.util.Objects.requireNonNull(BuiltInRegistries.CUSTOM_STAT.getValue(entry.getKey()))); // Paper - ensured by SpigotConfig#stats -+ this.stats.put( wrapper, entry.getValue().intValue() ); -+ } -+ // Spigot end -+ // Paper end - Moved after stat fetching for player state file - } - - public void save() { -@@ -80,6 +85,7 @@ public class ServerStatsCounter extends StatsCounter { - @Override - public void setValue(Player player, Stat stat, int value) { - if ( org.spigotmc.SpigotConfig.disableStatSaving ) return; // Spigot -+ if (stat.getType() == Stats.CUSTOM && stat.getValue() instanceof final ResourceLocation resourceLocation && org.spigotmc.SpigotConfig.forcedStats.get(resourceLocation) != null) return; // Paper - disable saving forced stats - super.setValue(player, stat, value); - this.dirty.add(stat); - } diff --git a/patches/server/0876-Add-missing-InventoryHolders-to-inventories.patch b/patches/server/0876-Add-missing-InventoryHolders-to-inventories.patch deleted file mode 100644 index d6bf23a4f8..0000000000 --- a/patches/server/0876-Add-missing-InventoryHolders-to-inventories.patch +++ /dev/null @@ -1,314 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 24 Jan 2022 00:09:02 -0800 -Subject: [PATCH] Add missing InventoryHolders to inventories - - -diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java -index db41ffbd24adccd78edf3368ba1f7a3ab9f6072c..5db5ba026462ca642dcee718af732f80fadabef5 100644 ---- a/src/main/java/net/minecraft/world/Container.java -+++ b/src/main/java/net/minecraft/world/Container.java -@@ -103,7 +103,7 @@ public interface Container extends Clearable { - - java.util.List getViewers(); - -- org.bukkit.inventory.InventoryHolder getOwner(); -+ org.bukkit.inventory.@org.jetbrains.annotations.Nullable InventoryHolder getOwner(); // Paper - annotation - - void setMaxStackSize(int size); - -diff --git a/src/main/java/net/minecraft/world/SimpleContainer.java b/src/main/java/net/minecraft/world/SimpleContainer.java -index b0963c534afe5be164701cb283f1849e32ae5a86..7ed52b887c4d766c23220a8809914d5d80f12ea4 100644 ---- a/src/main/java/net/minecraft/world/SimpleContainer.java -+++ b/src/main/java/net/minecraft/world/SimpleContainer.java -@@ -30,7 +30,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible { - // CraftBukkit start - add fields and methods - public List transaction = new java.util.ArrayList(); - private int maxStack = MAX_STACK; -- protected org.bukkit.inventory.InventoryHolder bukkitOwner; -+ protected @Nullable org.bukkit.inventory.InventoryHolder bukkitOwner; // Paper - annotation - - public List getContents() { - return this.items; -@@ -58,6 +58,11 @@ public class SimpleContainer implements Container, StackedContentsCompatible { - } - - public org.bukkit.inventory.InventoryHolder getOwner() { -+ // Paper start - Add missing InventoryHolders -+ if (this.bukkitOwner == null && this.bukkitOwnerCreator != null) { -+ this.bukkitOwner = this.bukkitOwnerCreator.get(); -+ } -+ // Paper end - Add missing InventoryHolders - return this.bukkitOwner; - } - -@@ -86,6 +91,13 @@ public class SimpleContainer implements Container, StackedContentsCompatible { - public SimpleContainer(int size) { - this(size, null); - } -+ // Paper start - Add missing InventoryHolders -+ private @Nullable java.util.function.Supplier bukkitOwnerCreator; -+ public SimpleContainer(java.util.function.Supplier bukkitOwnerCreator, int size) { -+ this(size); -+ this.bukkitOwnerCreator = bukkitOwnerCreator; -+ } -+ // Paper end - Add missing InventoryHolders - - public SimpleContainer(int i, org.bukkit.inventory.InventoryHolder owner) { - this.bukkitOwner = owner; -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index 22dc1569aabe69f139d9682ceb81311993706cb8..85caec29a705f216eff8a5ae11f250697891a05c 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -1054,4 +1054,15 @@ public abstract class AbstractContainerMenu { - this.stateId = this.stateId + 1 & 32767; - return this.stateId; - } -+ -+ // Paper start - Add missing InventoryHolders -+ // The reason this is a supplier, is that the createHolder method uses the bukkit InventoryView#getTopInventory to get the inventory in question -+ // and that can't be obtained safely until the AbstractContainerMenu has been fully constructed. Using a supplier lazily -+ // initializes the InventoryHolder safely. -+ protected final Supplier createBlockHolder(final ContainerLevelAccess context) { -+ //noinspection ConstantValue -+ Preconditions.checkArgument(context != null, "context was null"); -+ return () -> context.createBlockHolder(this); -+ } -+ // Paper end - Add missing InventoryHolders - } -diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -index c0dfa04511110be366ee5b0bd75efc51afcce2e4..e0ee1c10960d24d2369d16f22431a8e02a5570aa 100644 ---- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -@@ -42,7 +42,7 @@ public class BeaconMenu extends AbstractContainerMenu { - public BeaconMenu(int syncId, Container inventory, ContainerData propertyDelegate, ContainerLevelAccess context) { - super(MenuType.BEACON, syncId); - this.player = (Inventory) inventory; // CraftBukkit - TODO: check this -- this.beacon = new SimpleContainer(1) { // CraftBukkit - decompile error -+ this.beacon = new SimpleContainer(this.createBlockHolder(context), 1) { // CraftBukkit - decompile error // Paper - Add missing InventoryHolders - @Override - public boolean canPlaceItem(int slot, ItemStack stack) { - return stack.is(ItemTags.BEACON_PAYMENT_ITEMS); -diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -index 8b72d1fd551dcb113f4137aee441a9531c00288a..b3a16b024e46ee8203b225ee429a5c973eab12c6 100644 ---- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -@@ -54,7 +54,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { - - public CartographyTableMenu(int syncId, Inventory inventory, final ContainerLevelAccess context) { - super(MenuType.CARTOGRAPHY_TABLE, syncId); -- this.container = new SimpleContainer(2) { -+ this.container = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { - CartographyTableMenu.this.slotsChanged(this); -@@ -68,7 +68,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { - } - // CraftBukkit end - }; -- this.resultContainer = new ResultContainer() { -+ this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { - CartographyTableMenu.this.slotsChanged(this); -diff --git a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java -index 85e336637db8643fc5aca1dba724c9b341cbf46f..12b466ccb7c36021cf807c4f3fd2bcb037943abc 100644 ---- a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java -+++ b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java -@@ -21,6 +21,18 @@ public interface ContainerLevelAccess { - return new org.bukkit.Location(this.getWorld().getWorld(), this.getPosition().getX(), this.getPosition().getY(), this.getPosition().getZ()); - } - // CraftBukkit end -+ // Paper start - Add missing InventoryHolders -+ default boolean isBlock() { -+ return false; -+ } -+ -+ default org.bukkit.inventory.@org.jetbrains.annotations.Nullable BlockInventoryHolder createBlockHolder(AbstractContainerMenu menu) { -+ if (!this.isBlock()) { -+ return null; -+ } -+ return new org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder(this, menu.getBukkitView().getTopInventory()); -+ } -+ // Paper end - Add missing InventoryHolders - - ContainerLevelAccess NULL = new ContainerLevelAccess() { - @Override -@@ -48,6 +60,12 @@ public interface ContainerLevelAccess { - return pos; - } - // CraftBukkit end -+ // Paper start - Add missing InventoryHolders -+ @Override -+ public boolean isBlock() { -+ return true; -+ } -+ // Paper end - Add missing InventoryHolders - - @Override - public Optional evaluate(BiFunction getter) { -diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -index 2642d8ddc79ad97675f958c89ef03da39903f359..36496144dd6fa87163b692034570eba70c83678c 100644 ---- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -63,7 +63,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { - - public EnchantmentMenu(int syncId, Inventory playerInventory, ContainerLevelAccess context) { - super(MenuType.ENCHANTMENT, syncId); -- this.enchantSlots = new SimpleContainer(2) { -+ this.enchantSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { - super.setChanged(); -diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -index 8e58dbb4b110338dfe8add26697d0b1c9ec5fa9c..3b303d41b9facfb2892ff8402ee0de4608db7318 100644 ---- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -@@ -60,8 +60,8 @@ public class GrindstoneMenu extends AbstractContainerMenu { - - public GrindstoneMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) { - super(MenuType.GRINDSTONE, syncId); -- this.resultSlots = new ResultContainer(); -- this.repairSlots = new SimpleContainer(2) { -+ this.resultSlots = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders -+ this.repairSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { - super.setChanged(); -diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -index 4734dd90f2a66e1ac7a64b35ecd62a630108cf07..a5d53a656513ae81cc3f9fc506caf6adaba62a8e 100644 ---- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -@@ -17,12 +17,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - protected final ContainerLevelAccess access; - protected final Player player; - protected final Container inputSlots; -- protected final ResultContainer resultSlots = new ResultContainer() { -- @Override -- public void setChanged() { -- ItemCombinerMenu.this.slotsChanged(this); -- } -- }; -+ protected final ResultContainer resultSlots; // Paper - Add missing InventoryHolders; delay field init - private final int resultSlotIndex; - - protected boolean mayPickup(Player player, boolean present) { -@@ -36,6 +31,14 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - public ItemCombinerMenu(@Nullable MenuType type, int syncId, Inventory playerInventory, ContainerLevelAccess context, ItemCombinerMenuSlotDefinition forgingSlotsManager) { - super(type, syncId); - this.access = context; -+ // Paper start - Add missing InventoryHolders; delay field init -+ this.resultSlots = new ResultContainer(this.createBlockHolder(this.access)) { -+ @Override -+ public void setChanged() { -+ ItemCombinerMenu.this.slotsChanged(this); -+ } -+ }; -+ // Paper end - Add missing InventoryHolders; delay field init - this.player = playerInventory.player; - this.inputSlots = this.createContainer(forgingSlotsManager.getNumOfInputSlots()); - this.resultSlotIndex = forgingSlotsManager.getResultSlotIndex(); -@@ -82,7 +85,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - public abstract void createResult(); - - private SimpleContainer createContainer(int size) { -- return new SimpleContainer(size) { -+ return new SimpleContainer(this.createBlockHolder(this.access), size) { - @Override - public void setChanged() { - super.setChanged(); -diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java -index 1b7cf165ab0818792870f43719a6324b282bb57a..98519dd3bccca516acdedc69a59189b1106fb75b 100644 ---- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java -@@ -73,7 +73,7 @@ public class LoomMenu extends AbstractContainerMenu { - this.selectablePatterns = List.of(); - this.slotUpdateListener = () -> { - }; -- this.inputContainer = new SimpleContainer(3) { -+ this.inputContainer = new SimpleContainer(this.createBlockHolder(context), 3) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { - super.setChanged(); -@@ -88,7 +88,7 @@ public class LoomMenu extends AbstractContainerMenu { - } - // CraftBukkit end - }; -- this.outputContainer = new SimpleContainer(1) { -+ this.outputContainer = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { - super.setChanged(); -diff --git a/src/main/java/net/minecraft/world/inventory/ResultContainer.java b/src/main/java/net/minecraft/world/inventory/ResultContainer.java -index d4592218d761eb38402e3d95c642e80a708cb333..4c4266a85c38e41e6c7e6144a68624f4daa50c54 100644 ---- a/src/main/java/net/minecraft/world/inventory/ResultContainer.java -+++ b/src/main/java/net/minecraft/world/inventory/ResultContainer.java -@@ -29,7 +29,12 @@ public class ResultContainer implements Container, RecipeCraftingHolder { - } - - public org.bukkit.inventory.InventoryHolder getOwner() { -- return null; // Result slots don't get an owner -+ // Paper start - Add missing InventoryHolders -+ if (this.holder == null && this.holderCreator != null) { -+ this.holder = this.holderCreator.get(); -+ } -+ return this.holder; // Result slots don't get an owner -+ // Paper end - Add missing InventoryHolders - } - - // Don't need a transaction; the InventoryCrafting keeps track of it for us -@@ -53,6 +58,14 @@ public class ResultContainer implements Container, RecipeCraftingHolder { - return null; - } - // CraftBukkit end -+ // Paper start - Add missing InventoryHolders -+ private @Nullable java.util.function.Supplier holderCreator; -+ private @Nullable org.bukkit.inventory.InventoryHolder holder; -+ public ResultContainer(java.util.function.Supplier holderCreator) { -+ this(); -+ this.holderCreator = holderCreator; -+ } -+ // Paper end - Add missing InventoryHolders - - public ResultContainer() { - this.itemStacks = NonNullList.withSize(1, ItemStack.EMPTY); -diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -index a93870952e2ef674028b8a20aa52a685c743e7ea..ca65965757e6f12abc972250a04817c7547bb0bd 100644 ---- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -@@ -69,7 +69,7 @@ public class StonecutterMenu extends AbstractContainerMenu { - this.input = ItemStack.EMPTY; - this.slotUpdateListener = () -> { - }; -- this.container = new SimpleContainer(1) { -+ this.container = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { - super.setChanged(); -@@ -84,7 +84,7 @@ public class StonecutterMenu extends AbstractContainerMenu { - } - // CraftBukkit end - }; -- this.resultContainer = new ResultContainer(); -+ this.resultContainer = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders - this.access = context; - this.level = playerInventory.player.level(); - this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33)); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java -index 7ae484b0fa5bf5494c6ead15f7f1c0fa840ae270..7129eb5f5cea39992b4c690cb421004004a952ea 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java -@@ -17,6 +17,13 @@ public class CraftBlockInventoryHolder implements BlockInventoryHolder { - this.block = CraftBlock.at(world, pos); - this.inventory = new CraftInventory(inv); - } -+ // Paper start - Add missing InventoryHolders -+ public CraftBlockInventoryHolder(net.minecraft.world.inventory.ContainerLevelAccess levelAccess, Inventory inventory) { -+ com.google.common.base.Preconditions.checkArgument(levelAccess.isBlock()); -+ this.block = CraftBlock.at(levelAccess.getWorld(), levelAccess.getPosition()); -+ this.inventory = inventory; -+ } -+ // Paper end - Add missing InventoryHolders - - @Override - public Block getBlock() { diff --git a/patches/server/0876-Do-not-read-tile-entities-in-chunks-that-are-positio.patch b/patches/server/0876-Do-not-read-tile-entities-in-chunks-that-are-positio.patch new file mode 100644 index 0000000000..c55e56d157 --- /dev/null +++ b/patches/server/0876-Do-not-read-tile-entities-in-chunks-that-are-positio.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 18 Jun 2023 23:04:46 -0700 +Subject: [PATCH] Do not read tile entities in chunks that are positioned + outside of the chunk + +The tile entities are not accessible and so should not be loaded. +This can happen as a result of users moving regionfiles around, +which would cause a crash on Folia but would appear to function +fine on Paper. + +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +index d7a204216332ccbd6bece23bd507be0366ea4d61..b86b3bf713668999a21c4120b1d16c295531b2ad 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +@@ -363,6 +363,13 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun + + while (iterator2.hasNext()) { + nbttagcompound = (CompoundTag) iterator2.next(); ++ // Paper start - do not read tile entities positioned outside the chunk ++ final BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound); ++ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { ++ LOGGER.warn("Tile entity serialized in chunk {} in world '{}' positioned at {} is located outside of the chunk", chunkPos, world.getWorld().getName(), blockposition); ++ continue; ++ } ++ // Paper end - do not read tile entities positioned outside the chunk + protochunk1.setBlockEntityNbt(nbttagcompound); + } + +@@ -616,6 +623,13 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun + chunk.setBlockEntityNbt(nbttagcompound); + } else { + BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound); ++ // Paper start - do not read tile entities positioned outside the chunk ++ ChunkPos chunkPos = chunk.getPos(); ++ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { ++ LOGGER.warn("Tile entity serialized in chunk " + chunkPos + " in world '" + world.getWorld().getName() + "' positioned at " + blockposition + " is located outside of the chunk"); ++ continue; ++ } ++ // Paper end - do not read tile entities positioned outside the chunk + BlockEntity tileentity = BlockEntity.loadStatic(blockposition, chunk.getBlockState(blockposition), nbttagcompound, world.registryAccess()); + + if (tileentity != null) { diff --git a/patches/server/0877-Add-missing-logs-for-log-ips-config-option.patch b/patches/server/0877-Add-missing-logs-for-log-ips-config-option.patch new file mode 100644 index 0000000000..2898d66615 --- /dev/null +++ b/patches/server/0877-Add-missing-logs-for-log-ips-config-option.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sat, 23 Sep 2023 01:49:39 -0400 +Subject: [PATCH] Add missing logs for log-ips config option + + +diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java +index d4f5a98a0b1ca9f2a8baa6e0b27353df94d1f333..569516822319c885e76be1aa92580bdf0bc932f5 100644 +--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java ++++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java +@@ -50,7 +50,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter { + com.destroystokyo.paper.event.server.PaperServerListPingEvent event; // Paper + + if (i == 0) { +- LegacyQueryHandler.LOGGER.debug("Ping: (<1.3.x) from {}", socketaddress); ++ LegacyQueryHandler.LOGGER.debug("Ping: (<1.3.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socketaddress: ""); // Paper - Respect logIPs option + + // Paper start - Call PaperServerListPingEvent and use results + event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), (java.net.InetSocketAddress) socketaddress, 39, null); +@@ -83,7 +83,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter { + // LegacyQueryHandler.LOGGER.debug("Ping: (1.6) from {}", socketaddress); + // Paper end + } else { +- LegacyQueryHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}", socketaddress); ++ LegacyQueryHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socketaddress: ""); // Paper - Respect logIPs option + } + + if (s == null) { +@@ -207,7 +207,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter { + buf.release(); + this.buf = null; + +- LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress()); ++ LOGGER.debug("Ping: (1.6) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? ctx.channel().remoteAddress(): ""); // Paper - Respect logIPs option + + java.net.InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port); + com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest( diff --git a/patches/server/0877-Do-not-read-tile-entities-in-chunks-that-are-positio.patch b/patches/server/0877-Do-not-read-tile-entities-in-chunks-that-are-positio.patch deleted file mode 100644 index c55e56d157..0000000000 --- a/patches/server/0877-Do-not-read-tile-entities-in-chunks-that-are-positio.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 18 Jun 2023 23:04:46 -0700 -Subject: [PATCH] Do not read tile entities in chunks that are positioned - outside of the chunk - -The tile entities are not accessible and so should not be loaded. -This can happen as a result of users moving regionfiles around, -which would cause a crash on Folia but would appear to function -fine on Paper. - -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index d7a204216332ccbd6bece23bd507be0366ea4d61..b86b3bf713668999a21c4120b1d16c295531b2ad 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -@@ -363,6 +363,13 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun - - while (iterator2.hasNext()) { - nbttagcompound = (CompoundTag) iterator2.next(); -+ // Paper start - do not read tile entities positioned outside the chunk -+ final BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound); -+ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { -+ LOGGER.warn("Tile entity serialized in chunk {} in world '{}' positioned at {} is located outside of the chunk", chunkPos, world.getWorld().getName(), blockposition); -+ continue; -+ } -+ // Paper end - do not read tile entities positioned outside the chunk - protochunk1.setBlockEntityNbt(nbttagcompound); - } - -@@ -616,6 +623,13 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun - chunk.setBlockEntityNbt(nbttagcompound); - } else { - BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound); -+ // Paper start - do not read tile entities positioned outside the chunk -+ ChunkPos chunkPos = chunk.getPos(); -+ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { -+ LOGGER.warn("Tile entity serialized in chunk " + chunkPos + " in world '" + world.getWorld().getName() + "' positioned at " + blockposition + " is located outside of the chunk"); -+ continue; -+ } -+ // Paper end - do not read tile entities positioned outside the chunk - BlockEntity tileentity = BlockEntity.loadStatic(blockposition, chunk.getBlockState(blockposition), nbttagcompound, world.registryAccess()); - - if (tileentity != null) { diff --git a/patches/server/0878-Add-missing-logs-for-log-ips-config-option.patch b/patches/server/0878-Add-missing-logs-for-log-ips-config-option.patch deleted file mode 100644 index 2898d66615..0000000000 --- a/patches/server/0878-Add-missing-logs-for-log-ips-config-option.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sat, 23 Sep 2023 01:49:39 -0400 -Subject: [PATCH] Add missing logs for log-ips config option - - -diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java -index d4f5a98a0b1ca9f2a8baa6e0b27353df94d1f333..569516822319c885e76be1aa92580bdf0bc932f5 100644 ---- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java -+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java -@@ -50,7 +50,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter { - com.destroystokyo.paper.event.server.PaperServerListPingEvent event; // Paper - - if (i == 0) { -- LegacyQueryHandler.LOGGER.debug("Ping: (<1.3.x) from {}", socketaddress); -+ LegacyQueryHandler.LOGGER.debug("Ping: (<1.3.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socketaddress: ""); // Paper - Respect logIPs option - - // Paper start - Call PaperServerListPingEvent and use results - event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), (java.net.InetSocketAddress) socketaddress, 39, null); -@@ -83,7 +83,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter { - // LegacyQueryHandler.LOGGER.debug("Ping: (1.6) from {}", socketaddress); - // Paper end - } else { -- LegacyQueryHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}", socketaddress); -+ LegacyQueryHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socketaddress: ""); // Paper - Respect logIPs option - } - - if (s == null) { -@@ -207,7 +207,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter { - buf.release(); - this.buf = null; - -- LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress()); -+ LOGGER.debug("Ping: (1.6) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? ctx.channel().remoteAddress(): ""); // Paper - Respect logIPs option - - java.net.InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port); - com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest( diff --git a/patches/server/0878-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch b/patches/server/0878-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch new file mode 100644 index 0000000000..b6ec32df61 --- /dev/null +++ b/patches/server/0878-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Tue, 8 Aug 2023 17:29:33 -0700 +Subject: [PATCH] Fix race condition on UpgradeData.BlockFixers class init + +The CHUNKY_FIXERS field is modified during the constructors +of the BlockFixers, but the code that uses CHUNKY_FIXERS does +not properly ensure that BlockFixers has been initialised before +using it, leading to a possible race condition where instances of +BlockFixers are accessed before they have initialised correctly. + +We can force the class to initialise fully before accessing the +field by calling any method on the class, and for convenience +we use values(). + +diff --git a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java +index ce3d79ebc7f933d0b34b3f8f71bbec872076847a..ce84851c0c2bf9a066fd5e07be8635d3dcaea0b9 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java ++++ b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java +@@ -153,6 +153,7 @@ public class UpgradeData { + Fluid fluid = tick.type() == Fluids.EMPTY ? level.getFluidState(tick.pos()).getType() : tick.type(); + level.scheduleTick(tick.pos(), fluid, tick.delay(), tick.priority()); + }); ++ UpgradeData.BlockFixers.values(); // Paper - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised + CHUNKY_FIXERS.forEach(logic -> logic.processChunk(level)); + } + diff --git a/patches/server/0879-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch b/patches/server/0879-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch new file mode 100644 index 0000000000..7ccf4c0f03 --- /dev/null +++ b/patches/server/0879-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 23 Sep 2023 22:07:15 -0700 +Subject: [PATCH] Fix NPE in AdvancementProgress#getDateAwarded + + +diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java +index aeb04a65a1201f05fd02151fce5756d797c63615..ec3b9cb901913b093c3eb0bda8dc0dbb738c165e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java ++++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java +@@ -44,7 +44,7 @@ public class CraftAdvancementProgress implements AdvancementProgress { + @Override + public Date getDateAwarded(String criteria) { + CriterionProgress criterion = this.handle.getCriterion(criteria); +- return (criterion == null) ? null : Date.from(criterion.getObtained()); ++ return (criterion == null) ? null : criterion.getObtained() == null ? null : Date.from(criterion.getObtained()); // Paper - fix NPE if criterion isn't obtained + } + + @Override diff --git a/patches/server/0879-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch b/patches/server/0879-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch deleted file mode 100644 index b6ec32df61..0000000000 --- a/patches/server/0879-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 8 Aug 2023 17:29:33 -0700 -Subject: [PATCH] Fix race condition on UpgradeData.BlockFixers class init - -The CHUNKY_FIXERS field is modified during the constructors -of the BlockFixers, but the code that uses CHUNKY_FIXERS does -not properly ensure that BlockFixers has been initialised before -using it, leading to a possible race condition where instances of -BlockFixers are accessed before they have initialised correctly. - -We can force the class to initialise fully before accessing the -field by calling any method on the class, and for convenience -we use values(). - -diff --git a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -index ce3d79ebc7f933d0b34b3f8f71bbec872076847a..ce84851c0c2bf9a066fd5e07be8635d3dcaea0b9 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -+++ b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -@@ -153,6 +153,7 @@ public class UpgradeData { - Fluid fluid = tick.type() == Fluids.EMPTY ? level.getFluidState(tick.pos()).getType() : tick.type(); - level.scheduleTick(tick.pos(), fluid, tick.delay(), tick.priority()); - }); -+ UpgradeData.BlockFixers.values(); // Paper - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised - CHUNKY_FIXERS.forEach(logic -> logic.processChunk(level)); - } - diff --git a/patches/server/0880-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch b/patches/server/0880-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch deleted file mode 100644 index 7ccf4c0f03..0000000000 --- a/patches/server/0880-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 23 Sep 2023 22:07:15 -0700 -Subject: [PATCH] Fix NPE in AdvancementProgress#getDateAwarded - - -diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java -index aeb04a65a1201f05fd02151fce5756d797c63615..ec3b9cb901913b093c3eb0bda8dc0dbb738c165e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java -+++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementProgress.java -@@ -44,7 +44,7 @@ public class CraftAdvancementProgress implements AdvancementProgress { - @Override - public Date getDateAwarded(String criteria) { - CriterionProgress criterion = this.handle.getCriterion(criteria); -- return (criterion == null) ? null : Date.from(criterion.getObtained()); -+ return (criterion == null) ? null : criterion.getObtained() == null ? null : Date.from(criterion.getObtained()); // Paper - fix NPE if criterion isn't obtained - } - - @Override diff --git a/patches/server/0880-Fix-team-sidebar-objectives-not-being-cleared.patch b/patches/server/0880-Fix-team-sidebar-objectives-not-being-cleared.patch new file mode 100644 index 0000000000..cebe7aefc2 --- /dev/null +++ b/patches/server/0880-Fix-team-sidebar-objectives-not-being-cleared.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 23 Sep 2023 22:31:54 -0700 +Subject: [PATCH] Fix team sidebar objectives not being cleared + +Objectives displayed in team sidebars were not cleared when switching +scoreboards. If a player's scoreboard has a displayed objective for the +'gold' sidebar, and their scoreboard was switched to one where they +still had a 'gold' team, it would still be displayed + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java +index c7ca6210d6ae37fe95068c9baa5fb654f95307e0..f3184be3853dfc4df4ae4b8af764dfef07628ef4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java +@@ -87,8 +87,8 @@ public final class CraftScoreboardManager implements ScoreboardManager { + + // Old objective tracking + HashSet removed = new HashSet<>(); +- for (int i = 0; i < 3; ++i) { +- Objective scoreboardobjective = oldboard.getDisplayObjective(net.minecraft.world.scores.DisplaySlot.BY_ID.apply(i)); ++ for (net.minecraft.world.scores.DisplaySlot slot : net.minecraft.world.scores.DisplaySlot.values()) { // Paper - clear all display slots ++ Objective scoreboardobjective = oldboard.getDisplayObjective(slot); // Paper - clear all display slots + if (scoreboardobjective != null && !removed.contains(scoreboardobjective)) { + entityplayer.connection.send(new ClientboundSetObjectivePacket(scoreboardobjective, 1)); + removed.add(scoreboardobjective); diff --git a/patches/server/0881-Fix-missing-map-initialize-event-call.patch b/patches/server/0881-Fix-missing-map-initialize-event-call.patch new file mode 100644 index 0000000000..0eb662ab82 --- /dev/null +++ b/patches/server/0881-Fix-missing-map-initialize-event-call.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Sun, 24 Sep 2023 18:35:28 +0200 +Subject: [PATCH] Fix missing map initialize event call + +== AT == +public net.minecraft.world.level.storage.DimensionDataStorage readSavedData(Ljava/util/function/Function;Lnet/minecraft/util/datafix/DataFixTypes;Ljava/lang/String;)Lnet/minecraft/world/level/saveddata/SavedData; + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 0db41d36d5daf015c750fb0246ab3e5da1cd81a2..7cecbac43f1cd2d9516034ea9d2633c0c76e61f4 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1696,13 +1696,29 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + @Nullable + @Override + public MapItemSavedData getMapData(MapId id) { +- // CraftBukkit start +- MapItemSavedData worldmap = (MapItemSavedData) this.getServer().overworld().getDataStorage().get(MapItemSavedData.factory(), id.key()); +- if (worldmap != null) { +- worldmap.id = id; ++ // Paper start - Call missing map initialize event and set id ++ final DimensionDataStorage storage = this.getServer().overworld().getDataStorage(); ++ ++ final Optional cacheEntry = storage.cache.get(id.key()); ++ if (cacheEntry == null) { // Cache did not contain, try to load and may init ++ final MapItemSavedData worldmap = storage.get(MapItemSavedData.factory(), id.key()); // get populates the cache ++ if (worldmap != null) { // map was read, init it and return ++ worldmap.id = id; ++ new MapInitializeEvent(worldmap.mapView).callEvent(); ++ return worldmap; ++ } ++ ++ return null; // Map does not exist, reading failed. + } +- return worldmap; +- // CraftBukkit end ++ ++ // Cache entry exists, update it with the id ref and return. ++ if (cacheEntry.orElse(null) instanceof final MapItemSavedData mapItemSavedData) { ++ mapItemSavedData.id = id; ++ return mapItemSavedData; ++ } ++ ++ return null; ++ // Paper end - Call missing map initialize event and set id + } + + @Override diff --git a/patches/server/0881-Fix-team-sidebar-objectives-not-being-cleared.patch b/patches/server/0881-Fix-team-sidebar-objectives-not-being-cleared.patch deleted file mode 100644 index 88a39d0b20..0000000000 --- a/patches/server/0881-Fix-team-sidebar-objectives-not-being-cleared.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 23 Sep 2023 22:31:54 -0700 -Subject: [PATCH] Fix team sidebar objectives not being cleared - -Objectives displayed in team sidebars were not cleared when switching -scoreboards. If a player's scoreboard has a displayed objective for the -'gold' sidebar, and their scoreboard was switched to one where they -still had a 'gold' team, it would still be displayed - -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -index cad42a0f3c016bf65181e50d139ae4e2fb9158a5..b3e1adeb932da9b3bed16acd94e2f16da48a7c72 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -@@ -87,8 +87,8 @@ public final class CraftScoreboardManager implements ScoreboardManager { - - // Old objective tracking - HashSet removed = new HashSet<>(); -- for (int i = 0; i < 3; ++i) { -- Objective scoreboardobjective = oldboard.getDisplayObjective(net.minecraft.world.scores.DisplaySlot.BY_ID.apply(i)); -+ for (net.minecraft.world.scores.DisplaySlot slot : net.minecraft.world.scores.DisplaySlot.values()) { // Paper - clear all display slots -+ Objective scoreboardobjective = oldboard.getDisplayObjective(slot); // Paper - clear all display slots - if (scoreboardobjective != null && !removed.contains(scoreboardobjective)) { - entityplayer.connection.send(new ClientboundSetObjectivePacket(scoreboardobjective, 1)); - removed.add(scoreboardobjective); diff --git a/patches/server/0882-Fix-missing-map-initialize-event-call.patch b/patches/server/0882-Fix-missing-map-initialize-event-call.patch deleted file mode 100644 index f2047845c6..0000000000 --- a/patches/server/0882-Fix-missing-map-initialize-event-call.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Sun, 24 Sep 2023 18:35:28 +0200 -Subject: [PATCH] Fix missing map initialize event call - -== AT == -public net.minecraft.world.level.storage.DimensionDataStorage readSavedData(Ljava/util/function/Function;Lnet/minecraft/util/datafix/DataFixTypes;Ljava/lang/String;)Lnet/minecraft/world/level/saveddata/SavedData; - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 9270584d74edf5c1af473b1a13f7edca74cc1ec7..1bacbb0d0bd5198d0f946a959b2335d6fba0ca88 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1726,13 +1726,29 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - @Nullable - @Override - public MapItemSavedData getMapData(MapId id) { -- // CraftBukkit start -- MapItemSavedData worldmap = (MapItemSavedData) this.getServer().overworld().getDataStorage().get(MapItemSavedData.factory(), id.key()); -- if (worldmap != null) { -- worldmap.id = id; -+ // Paper start - Call missing map initialize event and set id -+ final DimensionDataStorage storage = this.getServer().overworld().getDataStorage(); -+ -+ final Optional cacheEntry = storage.cache.get(id.key()); -+ if (cacheEntry == null) { // Cache did not contain, try to load and may init -+ final MapItemSavedData worldmap = storage.get(MapItemSavedData.factory(), id.key()); // get populates the cache -+ if (worldmap != null) { // map was read, init it and return -+ worldmap.id = id; -+ new MapInitializeEvent(worldmap.mapView).callEvent(); -+ return worldmap; -+ } -+ -+ return null; // Map does not exist, reading failed. - } -- return worldmap; -- // CraftBukkit end -+ -+ // Cache entry exists, update it with the id ref and return. -+ if (cacheEntry.orElse(null) instanceof final MapItemSavedData mapItemSavedData) { -+ mapItemSavedData.id = id; -+ return mapItemSavedData; -+ } -+ -+ return null; -+ // Paper end - Call missing map initialize event and set id - } - - @Override diff --git a/patches/server/0882-Update-entity-data-when-attaching-firework-to-entity.patch b/patches/server/0882-Update-entity-data-when-attaching-firework-to-entity.patch new file mode 100644 index 0000000000..f2c094976f --- /dev/null +++ b/patches/server/0882-Update-entity-data-when-attaching-firework-to-entity.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Sun, 27 Aug 2023 16:11:31 +0200 +Subject: [PATCH] Update entity data when attaching firework to entity + +== AT == +public net.minecraft.world.entity.projectile.FireworkRocketEntity DATA_ATTACHED_TO_TARGET + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java +index 2d54cf6f3d9696c55335f0a2057025e2034d4e13..759b6e54db93792c9862b1f1625118ac6fa49d7a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java +@@ -69,6 +69,10 @@ public class CraftFirework extends CraftProjectile implements Firework { + } + + this.getHandle().attachedToEntity = (entity != null) ? ((CraftLivingEntity) entity).getHandle() : null; ++ // Paper start - update entity data ++ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET, ++ entity != null ? java.util.OptionalInt.of(entity.getEntityId()) : java.util.OptionalInt.empty()); ++ // Paper end - update entity data + return true; + } + diff --git a/patches/server/0883-Fix-UnsafeValues-loadAdvancement.patch b/patches/server/0883-Fix-UnsafeValues-loadAdvancement.patch new file mode 100644 index 0000000000..dc4c28926e --- /dev/null +++ b/patches/server/0883-Fix-UnsafeValues-loadAdvancement.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: LemonCaramel +Date: Sun, 24 Sep 2023 20:19:44 +0900 +Subject: [PATCH] Fix UnsafeValues#loadAdvancement + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index a74784ddf63d316f253381ed803822a149e92bc7..1835f8cfda0222fadd9db31abfb7e85899051853 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -302,9 +302,30 @@ public final class CraftMagicNumbers implements UnsafeValues { + ResourceLocation minecraftkey = CraftNamespacedKey.toMinecraft(key); + + JsonElement jsonelement = JsonParser.parseString(advancement); +- net.minecraft.advancements.Advancement nms = net.minecraft.advancements.Advancement.CODEC.parse(JsonOps.INSTANCE, jsonelement).getOrThrow(JsonParseException::new); ++ final net.minecraft.resources.RegistryOps ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE); // Paper - use RegistryOps ++ final net.minecraft.advancements.Advancement nms = net.minecraft.advancements.Advancement.CODEC.parse(ops, jsonelement).getOrThrow(JsonParseException::new); // Paper - use RegistryOps + if (nms != null) { +- MinecraftServer.getServer().getAdvancements().advancements.put(minecraftkey, new AdvancementHolder(minecraftkey, nms)); ++ // Paper start - Fix throw UnsupportedOperationException ++ //MinecraftServer.getServer().getAdvancements().advancements.put(minecraftkey, new AdvancementHolder(minecraftkey, nms)); ++ final com.google.common.collect.ImmutableMap.Builder mapBuilder = com.google.common.collect.ImmutableMap.builder(); ++ mapBuilder.putAll(MinecraftServer.getServer().getAdvancements().advancements); ++ ++ final AdvancementHolder holder = new AdvancementHolder(minecraftkey, nms); ++ mapBuilder.put(minecraftkey, holder); ++ ++ MinecraftServer.getServer().getAdvancements().advancements = mapBuilder.build(); ++ final net.minecraft.advancements.AdvancementTree tree = MinecraftServer.getServer().getAdvancements().tree(); ++ tree.addAll(java.util.List.of(holder)); ++ ++ // recalculate advancement position ++ final net.minecraft.advancements.AdvancementNode node = tree.get(minecraftkey); ++ if (node != null) { ++ final net.minecraft.advancements.AdvancementNode root = node.root(); ++ if (root.holder().value().display().isPresent()) { ++ net.minecraft.advancements.TreeNodePosition.run(root); ++ } ++ } ++ // Paper end - Fix throw UnsupportedOperationException + Advancement bukkit = Bukkit.getAdvancement(key); + + if (bukkit != null) { diff --git a/patches/server/0883-Update-entity-data-when-attaching-firework-to-entity.patch b/patches/server/0883-Update-entity-data-when-attaching-firework-to-entity.patch deleted file mode 100644 index f2c094976f..0000000000 --- a/patches/server/0883-Update-entity-data-when-attaching-firework-to-entity.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: booky10 -Date: Sun, 27 Aug 2023 16:11:31 +0200 -Subject: [PATCH] Update entity data when attaching firework to entity - -== AT == -public net.minecraft.world.entity.projectile.FireworkRocketEntity DATA_ATTACHED_TO_TARGET - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java -index 2d54cf6f3d9696c55335f0a2057025e2034d4e13..759b6e54db93792c9862b1f1625118ac6fa49d7a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java -@@ -69,6 +69,10 @@ public class CraftFirework extends CraftProjectile implements Firework { - } - - this.getHandle().attachedToEntity = (entity != null) ? ((CraftLivingEntity) entity).getHandle() : null; -+ // Paper start - update entity data -+ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET, -+ entity != null ? java.util.OptionalInt.of(entity.getEntityId()) : java.util.OptionalInt.empty()); -+ // Paper end - update entity data - return true; - } - diff --git a/patches/server/0884-Add-player-idle-duration-API.patch b/patches/server/0884-Add-player-idle-duration-API.patch new file mode 100644 index 0000000000..3bf9d659b7 --- /dev/null +++ b/patches/server/0884-Add-player-idle-duration-API.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Sat, 14 Oct 2023 03:11:11 +0200 +Subject: [PATCH] Add player idle duration API + +Implements API for getting and resetting a player's idle duration. + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 3b2d7837486424a2d1759c4ba5d1b1d492e9ec48..b72d6395768a762cd72f2b98bc8cb2598dc286b9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -3449,6 +3449,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + // Paper end + ++ // Paper start ++ @Override ++ public Duration getIdleDuration() { ++ return Duration.ofMillis(net.minecraft.Util.getMillis() - this.getHandle().getLastActionTime()); ++ } ++ ++ @Override ++ public void resetIdleDuration() { ++ this.getHandle().resetLastActionTime(); ++ } ++ // Paper end ++ + public Player.Spigot spigot() + { + return this.spigot; diff --git a/patches/server/0884-Fix-UnsafeValues-loadAdvancement.patch b/patches/server/0884-Fix-UnsafeValues-loadAdvancement.patch deleted file mode 100644 index fa08d471ab..0000000000 --- a/patches/server/0884-Fix-UnsafeValues-loadAdvancement.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LemonCaramel -Date: Sun, 24 Sep 2023 20:19:44 +0900 -Subject: [PATCH] Fix UnsafeValues#loadAdvancement - - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 766ef49d72eef0ff80247a807db5379f7fc60302..3900f95f3ea41b010b8ea79c043fe322fa233461 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -308,9 +308,30 @@ public final class CraftMagicNumbers implements UnsafeValues { - ResourceLocation minecraftkey = CraftNamespacedKey.toMinecraft(key); - - JsonElement jsonelement = JsonParser.parseString(advancement); -- net.minecraft.advancements.Advancement nms = net.minecraft.advancements.Advancement.CODEC.parse(JsonOps.INSTANCE, jsonelement).getOrThrow(JsonParseException::new); -+ final net.minecraft.resources.RegistryOps ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE); // Paper - use RegistryOps -+ final net.minecraft.advancements.Advancement nms = net.minecraft.advancements.Advancement.CODEC.parse(ops, jsonelement).getOrThrow(JsonParseException::new); // Paper - use RegistryOps - if (nms != null) { -- MinecraftServer.getServer().getAdvancements().advancements.put(minecraftkey, new AdvancementHolder(minecraftkey, nms)); -+ // Paper start - Fix throw UnsupportedOperationException -+ //MinecraftServer.getServer().getAdvancements().advancements.put(minecraftkey, new AdvancementHolder(minecraftkey, nms)); -+ final com.google.common.collect.ImmutableMap.Builder mapBuilder = com.google.common.collect.ImmutableMap.builder(); -+ mapBuilder.putAll(MinecraftServer.getServer().getAdvancements().advancements); -+ -+ final AdvancementHolder holder = new AdvancementHolder(minecraftkey, nms); -+ mapBuilder.put(minecraftkey, holder); -+ -+ MinecraftServer.getServer().getAdvancements().advancements = mapBuilder.build(); -+ final net.minecraft.advancements.AdvancementTree tree = MinecraftServer.getServer().getAdvancements().tree(); -+ tree.addAll(java.util.List.of(holder)); -+ -+ // recalculate advancement position -+ final net.minecraft.advancements.AdvancementNode node = tree.get(minecraftkey); -+ if (node != null) { -+ final net.minecraft.advancements.AdvancementNode root = node.root(); -+ if (root.holder().value().display().isPresent()) { -+ net.minecraft.advancements.TreeNodePosition.run(root); -+ } -+ } -+ // Paper end - Fix throw UnsupportedOperationException - Advancement bukkit = Bukkit.getAdvancement(key); - - if (bukkit != null) { diff --git a/patches/server/0885-Add-player-idle-duration-API.patch b/patches/server/0885-Add-player-idle-duration-API.patch deleted file mode 100644 index 3bf9d659b7..0000000000 --- a/patches/server/0885-Add-player-idle-duration-API.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: booky10 -Date: Sat, 14 Oct 2023 03:11:11 +0200 -Subject: [PATCH] Add player idle duration API - -Implements API for getting and resetting a player's idle duration. - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 3b2d7837486424a2d1759c4ba5d1b1d492e9ec48..b72d6395768a762cd72f2b98bc8cb2598dc286b9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3449,6 +3449,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - // Paper end - -+ // Paper start -+ @Override -+ public Duration getIdleDuration() { -+ return Duration.ofMillis(net.minecraft.Util.getMillis() - this.getHandle().getLastActionTime()); -+ } -+ -+ @Override -+ public void resetIdleDuration() { -+ this.getHandle().resetLastActionTime(); -+ } -+ // Paper end -+ - public Player.Spigot spigot() - { - return this.spigot; diff --git a/patches/server/0885-Don-t-check-if-we-can-see-non-visible-entities.patch b/patches/server/0885-Don-t-check-if-we-can-see-non-visible-entities.patch new file mode 100644 index 0000000000..00d8ff96c1 --- /dev/null +++ b/patches/server/0885-Don-t-check-if-we-can-see-non-visible-entities.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brokkonaut +Date: Sat, 21 Oct 2023 20:52:57 +0100 +Subject: [PATCH] Don't check if we can see non-visible entities + + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 5da3eee41ba0cbec5932cf9a7dac53777a2463fb..bf6d5f9e23387da845d6fe246c9013ec4d13cfb1 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1590,7 +1590,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper end - Configurable entity tracking range by Y + + // CraftBukkit start - respect vanish API +- if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { ++ if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits + flag = false; + } + // CraftBukkit end diff --git a/patches/server/0886-Don-t-check-if-we-can-see-non-visible-entities.patch b/patches/server/0886-Don-t-check-if-we-can-see-non-visible-entities.patch deleted file mode 100644 index 5078fe7f01..0000000000 --- a/patches/server/0886-Don-t-check-if-we-can-see-non-visible-entities.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brokkonaut -Date: Sat, 21 Oct 2023 20:52:57 +0100 -Subject: [PATCH] Don't check if we can see non-visible entities - - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 502d73830ed87e06529f194090a4ffb895b2623c..95c70de2c9f0e26742c0d66ad6c3bcc310a923f6 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1596,7 +1596,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper end - Configurable entity tracking range by Y - - // CraftBukkit start - respect vanish API -- if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { -+ if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits - flag = false; - } - // CraftBukkit end diff --git a/patches/server/0886-Fix-NPE-in-SculkBloomEvent-world-access.patch b/patches/server/0886-Fix-NPE-in-SculkBloomEvent-world-access.patch new file mode 100644 index 0000000000..3f44bad4f1 --- /dev/null +++ b/patches/server/0886-Fix-NPE-in-SculkBloomEvent-world-access.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Fri, 20 Oct 2023 19:50:22 +0200 +Subject: [PATCH] Fix NPE in SculkBloomEvent world access + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +index da81f76a2ee779ffedf9a02d91b5971004167725..4729befa12732a9fd65cce243b33b3b479026c41 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +@@ -35,9 +35,16 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi + public SculkCatalystBlockEntity(BlockPos pos, BlockState state) { + super(BlockEntityType.SCULK_CATALYST, pos, state); + this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(state, new BlockPositionSource(pos)); +- this.catalystListener.level = this.level; // CraftBukkit + } + ++ // Paper start - Fix NPE in SculkBloomEvent world access ++ @Override ++ public void setLevel(Level level) { ++ super.setLevel(level); ++ this.catalystListener.sculkSpreader.level = level; ++ } ++ // Paper end - Fix NPE in SculkBloomEvent world access ++ + public static void serverTick(Level world, BlockPos pos, BlockState state, SculkCatalystBlockEntity blockEntity) { + org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = blockEntity.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. + blockEntity.catalystListener.getSculkSpreader().updateCursors(world, pos, world.getRandom(), true); +@@ -67,13 +74,12 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi + final SculkSpreader sculkSpreader; + private final BlockState blockState; + private final PositionSource positionSource; +- private Level level; // CraftBukkit + + public CatalystListener(BlockState state, PositionSource positionSource) { + this.blockState = state; + this.positionSource = positionSource; + this.sculkSpreader = SculkSpreader.createLevelSpreader(); +- this.sculkSpreader.level = this.level; // CraftBukkit ++ // this.sculkSpreader.level = this.level; // CraftBukkit // Paper - Fix NPE in SculkBloomEvent world access + } + + @Override diff --git a/patches/server/0887-Allow-null-itemstack-for-Player-sendEquipmentChange.patch b/patches/server/0887-Allow-null-itemstack-for-Player-sendEquipmentChange.patch new file mode 100644 index 0000000000..c5594fd831 --- /dev/null +++ b/patches/server/0887-Allow-null-itemstack-for-Player-sendEquipmentChange.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Scandurra +Date: Wed, 25 Oct 2023 20:36:25 +0200 +Subject: [PATCH] Allow null itemstack for Player#sendEquipmentChange + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index b72d6395768a762cd72f2b98bc8cb2598dc286b9..542c2d85da9695da0f8cc5c34f2e3c0b925dfb7c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1144,7 +1144,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public void sendEquipmentChange(LivingEntity entity, EquipmentSlot slot, ItemStack item) { +- this.sendEquipmentChange(entity, Map.of(slot, item)); ++ this.sendEquipmentChange(entity, java.util.Collections.singletonMap(slot, item)); // Paper - replace Map.of to allow null values + } + + @Override diff --git a/patches/server/0887-Fix-NPE-in-SculkBloomEvent-world-access.patch b/patches/server/0887-Fix-NPE-in-SculkBloomEvent-world-access.patch deleted file mode 100644 index 3f44bad4f1..0000000000 --- a/patches/server/0887-Fix-NPE-in-SculkBloomEvent-world-access.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Fri, 20 Oct 2023 19:50:22 +0200 -Subject: [PATCH] Fix NPE in SculkBloomEvent world access - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -index da81f76a2ee779ffedf9a02d91b5971004167725..4729befa12732a9fd65cce243b33b3b479026c41 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -@@ -35,9 +35,16 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi - public SculkCatalystBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.SCULK_CATALYST, pos, state); - this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(state, new BlockPositionSource(pos)); -- this.catalystListener.level = this.level; // CraftBukkit - } - -+ // Paper start - Fix NPE in SculkBloomEvent world access -+ @Override -+ public void setLevel(Level level) { -+ super.setLevel(level); -+ this.catalystListener.sculkSpreader.level = level; -+ } -+ // Paper end - Fix NPE in SculkBloomEvent world access -+ - public static void serverTick(Level world, BlockPos pos, BlockState state, SculkCatalystBlockEntity blockEntity) { - org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = blockEntity.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. - blockEntity.catalystListener.getSculkSpreader().updateCursors(world, pos, world.getRandom(), true); -@@ -67,13 +74,12 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi - final SculkSpreader sculkSpreader; - private final BlockState blockState; - private final PositionSource positionSource; -- private Level level; // CraftBukkit - - public CatalystListener(BlockState state, PositionSource positionSource) { - this.blockState = state; - this.positionSource = positionSource; - this.sculkSpreader = SculkSpreader.createLevelSpreader(); -- this.sculkSpreader.level = this.level; // CraftBukkit -+ // this.sculkSpreader.level = this.level; // CraftBukkit // Paper - Fix NPE in SculkBloomEvent world access - } - - @Override diff --git a/patches/server/0888-Allow-null-itemstack-for-Player-sendEquipmentChange.patch b/patches/server/0888-Allow-null-itemstack-for-Player-sendEquipmentChange.patch deleted file mode 100644 index c5594fd831..0000000000 --- a/patches/server/0888-Allow-null-itemstack-for-Player-sendEquipmentChange.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Scandurra -Date: Wed, 25 Oct 2023 20:36:25 +0200 -Subject: [PATCH] Allow null itemstack for Player#sendEquipmentChange - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index b72d6395768a762cd72f2b98bc8cb2598dc286b9..542c2d85da9695da0f8cc5c34f2e3c0b925dfb7c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1144,7 +1144,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void sendEquipmentChange(LivingEntity entity, EquipmentSlot slot, ItemStack item) { -- this.sendEquipmentChange(entity, Map.of(slot, item)); -+ this.sendEquipmentChange(entity, java.util.Collections.singletonMap(slot, item)); // Paper - replace Map.of to allow null values - } - - @Override diff --git a/patches/server/0888-Optimize-VarInts.patch b/patches/server/0888-Optimize-VarInts.patch new file mode 100644 index 0000000000..b96957d432 --- /dev/null +++ b/patches/server/0888-Optimize-VarInts.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: astei +Date: Sat, 28 Oct 2023 19:46:21 -0400 +Subject: [PATCH] Optimize VarInts + +https://github.com/PaperMC/Paper/pull/6957#issuecomment-985250854 + +diff --git a/src/main/java/net/minecraft/network/VarInt.java b/src/main/java/net/minecraft/network/VarInt.java +index 49a8ddc269d53458cfbd639b7de838c2e5765748..74ed47659d3e615c2dae7da98d5a8cf1559625bf 100644 +--- a/src/main/java/net/minecraft/network/VarInt.java ++++ b/src/main/java/net/minecraft/network/VarInt.java +@@ -9,6 +9,18 @@ public class VarInt { + private static final int DATA_BITS_PER_BYTE = 7; + + public static int getByteSize(int i) { ++ // Paper start - Optimize VarInts ++ return VARINT_EXACT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(i)]; ++ } ++ private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33]; ++ static { ++ for (int i = 0; i <= 32; ++i) { ++ VARINT_EXACT_BYTE_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d); ++ } ++ VARINT_EXACT_BYTE_LENGTHS[32] = 1; // Special case for the number 0. ++ } ++ public static int getByteSizeOld(int i) { ++ // Paper end - Optimize VarInts + for (int j = 1; j < 5; j++) { + if ((i & -1 << j * 7) == 0) { + return j; +@@ -39,6 +51,21 @@ public class VarInt { + } + + public static ByteBuf write(ByteBuf buf, int i) { ++ // Paper start - Optimize VarInts ++ // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes ++ // that the proxy will write, to improve inlining. ++ if ((i & (0xFFFFFFFF << 7)) == 0) { ++ buf.writeByte(i); ++ } else if ((i & (0xFFFFFFFF << 14)) == 0) { ++ int w = (i & 0x7F | 0x80) << 8 | (i >>> 7); ++ buf.writeShort(w); ++ } else { ++ writeOld(buf, i); ++ } ++ return buf; ++ } ++ public static ByteBuf writeOld(ByteBuf buf, int i) { ++ // Paper end - Optimize VarInts + while ((i & -128) != 0) { + buf.writeByte(i & 127 | 128); + i >>>= 7; diff --git a/patches/server/0889-Add-API-to-get-the-collision-shape-of-a-block-before.patch b/patches/server/0889-Add-API-to-get-the-collision-shape-of-a-block-before.patch new file mode 100644 index 0000000000..50464e50cb --- /dev/null +++ b/patches/server/0889-Add-API-to-get-the-collision-shape-of-a-block-before.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TrollyLoki +Date: Wed, 11 Oct 2023 00:45:53 -0400 +Subject: [PATCH] Add API to get the collision shape of a block before it's + placed + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +index 3ec64c995dcb59a758741e32b886925983a8be56..50fb7edd25c1b38f5c463b78d21d4583bdc89229 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +@@ -683,6 +683,20 @@ public class CraftBlockData implements BlockData { + return this.state.isFaceSturdy(EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CraftBlock.blockFaceToNotch(face), CraftBlockSupport.toNMS(support)); + } + ++ // Paper start ++ @Override ++ public org.bukkit.util.VoxelShape getCollisionShape(Location location) { ++ Preconditions.checkArgument(location != null, "location must not be null"); ++ ++ CraftWorld world = (CraftWorld) location.getWorld(); ++ Preconditions.checkArgument(world != null, "location must not have a null world"); ++ ++ BlockPos position = CraftLocation.toBlockPosition(location); ++ net.minecraft.world.phys.shapes.VoxelShape shape = this.state.getCollisionShape(world.getHandle(), position); ++ return new org.bukkit.craftbukkit.util.CraftVoxelShape(shape); ++ } ++ // Paper end ++ + @Override + public Color getMapColor() { + return Color.fromRGB(this.state.getMapColor(null, null).col); diff --git a/patches/server/0889-Optimize-VarInts.patch b/patches/server/0889-Optimize-VarInts.patch deleted file mode 100644 index b96957d432..0000000000 --- a/patches/server/0889-Optimize-VarInts.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: astei -Date: Sat, 28 Oct 2023 19:46:21 -0400 -Subject: [PATCH] Optimize VarInts - -https://github.com/PaperMC/Paper/pull/6957#issuecomment-985250854 - -diff --git a/src/main/java/net/minecraft/network/VarInt.java b/src/main/java/net/minecraft/network/VarInt.java -index 49a8ddc269d53458cfbd639b7de838c2e5765748..74ed47659d3e615c2dae7da98d5a8cf1559625bf 100644 ---- a/src/main/java/net/minecraft/network/VarInt.java -+++ b/src/main/java/net/minecraft/network/VarInt.java -@@ -9,6 +9,18 @@ public class VarInt { - private static final int DATA_BITS_PER_BYTE = 7; - - public static int getByteSize(int i) { -+ // Paper start - Optimize VarInts -+ return VARINT_EXACT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(i)]; -+ } -+ private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33]; -+ static { -+ for (int i = 0; i <= 32; ++i) { -+ VARINT_EXACT_BYTE_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d); -+ } -+ VARINT_EXACT_BYTE_LENGTHS[32] = 1; // Special case for the number 0. -+ } -+ public static int getByteSizeOld(int i) { -+ // Paper end - Optimize VarInts - for (int j = 1; j < 5; j++) { - if ((i & -1 << j * 7) == 0) { - return j; -@@ -39,6 +51,21 @@ public class VarInt { - } - - public static ByteBuf write(ByteBuf buf, int i) { -+ // Paper start - Optimize VarInts -+ // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes -+ // that the proxy will write, to improve inlining. -+ if ((i & (0xFFFFFFFF << 7)) == 0) { -+ buf.writeByte(i); -+ } else if ((i & (0xFFFFFFFF << 14)) == 0) { -+ int w = (i & 0x7F | 0x80) << 8 | (i >>> 7); -+ buf.writeShort(w); -+ } else { -+ writeOld(buf, i); -+ } -+ return buf; -+ } -+ public static ByteBuf writeOld(ByteBuf buf, int i) { -+ // Paper end - Optimize VarInts - while ((i & -128) != 0) { - buf.writeByte(i & 127 | 128); - i >>>= 7; diff --git a/patches/server/0890-Add-API-to-get-the-collision-shape-of-a-block-before.patch b/patches/server/0890-Add-API-to-get-the-collision-shape-of-a-block-before.patch deleted file mode 100644 index 50464e50cb..0000000000 --- a/patches/server/0890-Add-API-to-get-the-collision-shape-of-a-block-before.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TrollyLoki -Date: Wed, 11 Oct 2023 00:45:53 -0400 -Subject: [PATCH] Add API to get the collision shape of a block before it's - placed - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -index 3ec64c995dcb59a758741e32b886925983a8be56..50fb7edd25c1b38f5c463b78d21d4583bdc89229 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -@@ -683,6 +683,20 @@ public class CraftBlockData implements BlockData { - return this.state.isFaceSturdy(EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CraftBlock.blockFaceToNotch(face), CraftBlockSupport.toNMS(support)); - } - -+ // Paper start -+ @Override -+ public org.bukkit.util.VoxelShape getCollisionShape(Location location) { -+ Preconditions.checkArgument(location != null, "location must not be null"); -+ -+ CraftWorld world = (CraftWorld) location.getWorld(); -+ Preconditions.checkArgument(world != null, "location must not have a null world"); -+ -+ BlockPos position = CraftLocation.toBlockPosition(location); -+ net.minecraft.world.phys.shapes.VoxelShape shape = this.state.getCollisionShape(world.getHandle(), position); -+ return new org.bukkit.craftbukkit.util.CraftVoxelShape(shape); -+ } -+ // Paper end -+ - @Override - public Color getMapColor() { - return Color.fromRGB(this.state.getMapColor(null, null).col); diff --git a/patches/server/0890-Add-predicate-for-blocks-when-raytracing.patch b/patches/server/0890-Add-predicate-for-blocks-when-raytracing.patch new file mode 100644 index 0000000000..fdeae8627c --- /dev/null +++ b/patches/server/0890-Add-predicate-for-blocks-when-raytracing.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TonytheMacaroni +Date: Wed, 6 Sep 2023 19:24:16 -0400 +Subject: [PATCH] Add predicate for blocks when raytracing + + +diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java +index 7e1a332168357b9af14dbe3299549c2c93903fa6..93738c7dea1ea3d19013a47380391274612a719b 100644 +--- a/src/main/java/net/minecraft/world/level/BlockGetter.java ++++ b/src/main/java/net/minecraft/world/level/BlockGetter.java +@@ -71,6 +71,12 @@ public interface BlockGetter extends LevelHeightAccessor { + + // CraftBukkit start - moved block handling into separate method for use by Block#rayTrace + default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) { ++ // Paper start - Add predicate for blocks when raytracing ++ return clip(raytrace1, blockposition, null); ++ } ++ ++ default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition, java.util.function.Predicate canCollide) { ++ // Paper end - Add predicate for blocks when raytracing + // Paper start - Prevent raytrace from loading chunks + BlockState iblockdata = this.getBlockStateIfLoaded(blockposition); + if (iblockdata == null) { +@@ -80,7 +86,7 @@ public interface BlockGetter extends LevelHeightAccessor { + return BlockHitResult.miss(raytrace1.getTo(), Direction.getApproximateNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo())); + } + // Paper end - Prevent raytrace from loading chunks +- if (iblockdata.isAir()) return null; // Paper - Perf: optimise air cases ++ if (iblockdata.isAir() || (canCollide != null && this instanceof LevelAccessor levelAccessor && !canCollide.test(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, blockposition)))) return null; // Paper - Perf: optimise air cases & check canCollide predicate + FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: don't need to go to world state again + Vec3 vec3d = raytrace1.getFrom(); + Vec3 vec3d1 = raytrace1.getTo(); +@@ -96,8 +102,14 @@ public interface BlockGetter extends LevelHeightAccessor { + // CraftBukkit end + + default BlockHitResult clip(ClipContext context) { ++ // Paper start - Add predicate for blocks when raytracing ++ return clip(context, (java.util.function.Predicate) null); ++ } ++ ++ default BlockHitResult clip(ClipContext context, java.util.function.Predicate canCollide) { ++ // Paper end - Add predicate for blocks when raytracing + return (BlockHitResult) BlockGetter.traverseBlocks(context.getFrom(), context.getTo(), context, (raytrace1, blockposition) -> { +- return this.clip(raytrace1, blockposition); // CraftBukkit - moved into separate method ++ return this.clip(raytrace1, blockposition, canCollide); // CraftBukkit - moved into separate method // Paper - Add predicate for blocks when raytracing + }, (raytrace1) -> { + Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo()); + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 188bd33f46b6baaa3fc21c9da6fa9a9d004e899e..041a6042a91f2a8933d7f9bcb44bb78894ffd405 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1116,9 +1116,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public RayTraceResult rayTraceEntities(Location start, Vector direction, double maxDistance, double raySize, Predicate filter) { ++ // Paper start - Add predicate for blocks when raytracing ++ return rayTraceEntities((io.papermc.paper.math.Position) start, direction, maxDistance, raySize, filter); ++ } ++ ++ public RayTraceResult rayTraceEntities(io.papermc.paper.math.Position start, Vector direction, double maxDistance, double raySize, Predicate filter) { + Preconditions.checkArgument(start != null, "Location start cannot be null"); +- Preconditions.checkArgument(this.equals(start.getWorld()), "Location start cannot be in a different world"); +- start.checkFinite(); ++ Preconditions.checkArgument(!(start instanceof Location location) || this.equals(location.getWorld()), "Location start cannot be in a different world"); ++ Preconditions.checkArgument(start.isFinite(), "Location start is not finite"); ++ // Paper end - Add predicate for blocks when raytracing + + Preconditions.checkArgument(direction != null, "Vector direction cannot be null"); + direction.checkFinite(); +@@ -1168,9 +1174,16 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public RayTraceResult rayTraceBlocks(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks) { ++ // Paper start - Add predicate for blocks when raytracing ++ return this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, null); ++ } ++ ++ @Override ++ public RayTraceResult rayTraceBlocks(io.papermc.paper.math.Position start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, Predicate canCollide) { + Preconditions.checkArgument(start != null, "Location start cannot be null"); +- Preconditions.checkArgument(this.equals(start.getWorld()), "Location start cannot be in a different world"); +- start.checkFinite(); ++ Preconditions.checkArgument(!(start instanceof Location location) || this.equals(location.getWorld()), "Location start cannot be in a different world"); ++ Preconditions.checkArgument(start.isFinite(), "Location start is not finite"); ++ // Paper end - Add predicate for blocks when raytracing + + Preconditions.checkArgument(direction != null, "Vector direction cannot be null"); + direction.checkFinite(); +@@ -1183,16 +1196,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { + } + + Vector dir = direction.clone().normalize().multiply(maxDistance); +- Vec3 startPos = CraftLocation.toVec3D(start); ++ Vec3 startPos = io.papermc.paper.util.MCUtil.toVec3(start); // Paper - Add predicate for blocks when raytracing + Vec3 endPos = startPos.add(dir.getX(), dir.getY(), dir.getZ()); +- HitResult nmsHitResult = this.getHandle().clip(new ClipContext(startPos, endPos, ignorePassableBlocks ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toNMS(fluidCollisionMode), CollisionContext.empty())); ++ HitResult nmsHitResult = this.getHandle().clip(new ClipContext(startPos, endPos, ignorePassableBlocks ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toNMS(fluidCollisionMode), CollisionContext.empty()), canCollide); // Paper - Add predicate for blocks when raytracing + + return CraftRayTraceResult.fromNMS(this, nmsHitResult); + } + + @Override + public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, Predicate filter) { +- RayTraceResult blockHit = this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks); ++ // Paper start - Add predicate for blocks when raytracing ++ return this.rayTrace(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, raySize, filter, null); ++ } ++ ++ @Override ++ public RayTraceResult rayTrace(io.papermc.paper.math.Position start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, Predicate filter, Predicate canCollide) { ++ RayTraceResult blockHit = this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, canCollide); ++ // Paper end - Add predicate for blocks when raytracing + Vector startVec = null; + double blockHitDistance = maxDistance; + diff --git a/patches/server/0891-Add-predicate-for-blocks-when-raytracing.patch b/patches/server/0891-Add-predicate-for-blocks-when-raytracing.patch deleted file mode 100644 index fdeae8627c..0000000000 --- a/patches/server/0891-Add-predicate-for-blocks-when-raytracing.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TonytheMacaroni -Date: Wed, 6 Sep 2023 19:24:16 -0400 -Subject: [PATCH] Add predicate for blocks when raytracing - - -diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java -index 7e1a332168357b9af14dbe3299549c2c93903fa6..93738c7dea1ea3d19013a47380391274612a719b 100644 ---- a/src/main/java/net/minecraft/world/level/BlockGetter.java -+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java -@@ -71,6 +71,12 @@ public interface BlockGetter extends LevelHeightAccessor { - - // CraftBukkit start - moved block handling into separate method for use by Block#rayTrace - default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) { -+ // Paper start - Add predicate for blocks when raytracing -+ return clip(raytrace1, blockposition, null); -+ } -+ -+ default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition, java.util.function.Predicate canCollide) { -+ // Paper end - Add predicate for blocks when raytracing - // Paper start - Prevent raytrace from loading chunks - BlockState iblockdata = this.getBlockStateIfLoaded(blockposition); - if (iblockdata == null) { -@@ -80,7 +86,7 @@ public interface BlockGetter extends LevelHeightAccessor { - return BlockHitResult.miss(raytrace1.getTo(), Direction.getApproximateNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo())); - } - // Paper end - Prevent raytrace from loading chunks -- if (iblockdata.isAir()) return null; // Paper - Perf: optimise air cases -+ if (iblockdata.isAir() || (canCollide != null && this instanceof LevelAccessor levelAccessor && !canCollide.test(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, blockposition)))) return null; // Paper - Perf: optimise air cases & check canCollide predicate - FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: don't need to go to world state again - Vec3 vec3d = raytrace1.getFrom(); - Vec3 vec3d1 = raytrace1.getTo(); -@@ -96,8 +102,14 @@ public interface BlockGetter extends LevelHeightAccessor { - // CraftBukkit end - - default BlockHitResult clip(ClipContext context) { -+ // Paper start - Add predicate for blocks when raytracing -+ return clip(context, (java.util.function.Predicate) null); -+ } -+ -+ default BlockHitResult clip(ClipContext context, java.util.function.Predicate canCollide) { -+ // Paper end - Add predicate for blocks when raytracing - return (BlockHitResult) BlockGetter.traverseBlocks(context.getFrom(), context.getTo(), context, (raytrace1, blockposition) -> { -- return this.clip(raytrace1, blockposition); // CraftBukkit - moved into separate method -+ return this.clip(raytrace1, blockposition, canCollide); // CraftBukkit - moved into separate method // Paper - Add predicate for blocks when raytracing - }, (raytrace1) -> { - Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo()); - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 188bd33f46b6baaa3fc21c9da6fa9a9d004e899e..041a6042a91f2a8933d7f9bcb44bb78894ffd405 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1116,9 +1116,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public RayTraceResult rayTraceEntities(Location start, Vector direction, double maxDistance, double raySize, Predicate filter) { -+ // Paper start - Add predicate for blocks when raytracing -+ return rayTraceEntities((io.papermc.paper.math.Position) start, direction, maxDistance, raySize, filter); -+ } -+ -+ public RayTraceResult rayTraceEntities(io.papermc.paper.math.Position start, Vector direction, double maxDistance, double raySize, Predicate filter) { - Preconditions.checkArgument(start != null, "Location start cannot be null"); -- Preconditions.checkArgument(this.equals(start.getWorld()), "Location start cannot be in a different world"); -- start.checkFinite(); -+ Preconditions.checkArgument(!(start instanceof Location location) || this.equals(location.getWorld()), "Location start cannot be in a different world"); -+ Preconditions.checkArgument(start.isFinite(), "Location start is not finite"); -+ // Paper end - Add predicate for blocks when raytracing - - Preconditions.checkArgument(direction != null, "Vector direction cannot be null"); - direction.checkFinite(); -@@ -1168,9 +1174,16 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public RayTraceResult rayTraceBlocks(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks) { -+ // Paper start - Add predicate for blocks when raytracing -+ return this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, null); -+ } -+ -+ @Override -+ public RayTraceResult rayTraceBlocks(io.papermc.paper.math.Position start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, Predicate canCollide) { - Preconditions.checkArgument(start != null, "Location start cannot be null"); -- Preconditions.checkArgument(this.equals(start.getWorld()), "Location start cannot be in a different world"); -- start.checkFinite(); -+ Preconditions.checkArgument(!(start instanceof Location location) || this.equals(location.getWorld()), "Location start cannot be in a different world"); -+ Preconditions.checkArgument(start.isFinite(), "Location start is not finite"); -+ // Paper end - Add predicate for blocks when raytracing - - Preconditions.checkArgument(direction != null, "Vector direction cannot be null"); - direction.checkFinite(); -@@ -1183,16 +1196,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { - } - - Vector dir = direction.clone().normalize().multiply(maxDistance); -- Vec3 startPos = CraftLocation.toVec3D(start); -+ Vec3 startPos = io.papermc.paper.util.MCUtil.toVec3(start); // Paper - Add predicate for blocks when raytracing - Vec3 endPos = startPos.add(dir.getX(), dir.getY(), dir.getZ()); -- HitResult nmsHitResult = this.getHandle().clip(new ClipContext(startPos, endPos, ignorePassableBlocks ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toNMS(fluidCollisionMode), CollisionContext.empty())); -+ HitResult nmsHitResult = this.getHandle().clip(new ClipContext(startPos, endPos, ignorePassableBlocks ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toNMS(fluidCollisionMode), CollisionContext.empty()), canCollide); // Paper - Add predicate for blocks when raytracing - - return CraftRayTraceResult.fromNMS(this, nmsHitResult); - } - - @Override - public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, Predicate filter) { -- RayTraceResult blockHit = this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks); -+ // Paper start - Add predicate for blocks when raytracing -+ return this.rayTrace(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, raySize, filter, null); -+ } -+ -+ @Override -+ public RayTraceResult rayTrace(io.papermc.paper.math.Position start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, Predicate filter, Predicate canCollide) { -+ RayTraceResult blockHit = this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, canCollide); -+ // Paper end - Add predicate for blocks when raytracing - Vector startVec = null; - double blockHitDistance = maxDistance; - diff --git a/patches/server/0891-Broadcast-take-item-packets-with-collector-as-source.patch b/patches/server/0891-Broadcast-take-item-packets-with-collector-as-source.patch new file mode 100644 index 0000000000..1fb19203b6 --- /dev/null +++ b/patches/server/0891-Broadcast-take-item-packets-with-collector-as-source.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Sun, 29 Oct 2023 02:36:10 +0100 +Subject: [PATCH] Broadcast take item packets with collector as source + +This fixes players (which can't view the collector) seeing item pickups with themselves as the target. + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 24245cfb160dc990b3661388c2f95b9383f98428..09bd6ba5907d42bed08872f18d40d8c743d392ff 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3891,7 +3891,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + + public void take(Entity item, int count) { + if (!item.isRemoved() && !this.level().isClientSide && (item instanceof ItemEntity || item instanceof AbstractArrow || item instanceof ExperienceOrb)) { +- ((ServerLevel) this.level()).getChunkSource().broadcast(item, new ClientboundTakeItemEntityPacket(item.getId(), this.getId(), count)); ++ ((ServerLevel) this.level()).getChunkSource().broadcastAndSend(this, new ClientboundTakeItemEntityPacket(item.getId(), this.getId(), count)); // Paper - broadcast with collector as source + } + + } diff --git a/patches/server/0892-Broadcast-take-item-packets-with-collector-as-source.patch b/patches/server/0892-Broadcast-take-item-packets-with-collector-as-source.patch deleted file mode 100644 index 03d6650dc1..0000000000 --- a/patches/server/0892-Broadcast-take-item-packets-with-collector-as-source.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: booky10 -Date: Sun, 29 Oct 2023 02:36:10 +0100 -Subject: [PATCH] Broadcast take item packets with collector as source - -This fixes players (which can't view the collector) seeing item pickups with themselves as the target. - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index a4d24269c1365f32f232116f1530ac75b096c6ab..30424789ba1c8d25f830145501b4a7399b91f2d1 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3893,7 +3893,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - - public void take(Entity item, int count) { - if (!item.isRemoved() && !this.level().isClientSide && (item instanceof ItemEntity || item instanceof AbstractArrow || item instanceof ExperienceOrb)) { -- ((ServerLevel) this.level()).getChunkSource().broadcast(item, new ClientboundTakeItemEntityPacket(item.getId(), this.getId(), count)); -+ ((ServerLevel) this.level()).getChunkSource().broadcastAndSend(this, new ClientboundTakeItemEntityPacket(item.getId(), this.getId(), count)); // Paper - broadcast with collector as source - } - - } diff --git a/patches/server/0892-Expand-LingeringPotion-API.patch b/patches/server/0892-Expand-LingeringPotion-API.patch new file mode 100644 index 0000000000..3a58f0528a --- /dev/null +++ b/patches/server/0892-Expand-LingeringPotion-API.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tamion <70228790+notTamion@users.noreply.github.com> +Date: Sat, 4 Nov 2023 23:57:05 +0100 +Subject: [PATCH] Expand LingeringPotion API + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +index e78eef3b6fbcd657f9dd180df4cb2eeb55d0814f..9d79b193fe2a737a20d1709548b2cd6c454ff27b 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +@@ -276,7 +276,7 @@ public class ThrownPotion extends ThrowableItemProjectile { + boolean noEffects = potioncontents.hasEffects(); // Paper - Fix potions splash events + // CraftBukkit start + org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, entityareaeffectcloud); +- if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (noEffects && !entityareaeffectcloud.potionContents.hasEffects()))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling ++ if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && !entityareaeffectcloud.potionContents.hasEffects())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling + this.level().addFreshEntity(entityareaeffectcloud); + } else { + entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause diff --git a/patches/server/0893-Expand-LingeringPotion-API.patch b/patches/server/0893-Expand-LingeringPotion-API.patch deleted file mode 100644 index 3a58f0528a..0000000000 --- a/patches/server/0893-Expand-LingeringPotion-API.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tamion <70228790+notTamion@users.noreply.github.com> -Date: Sat, 4 Nov 2023 23:57:05 +0100 -Subject: [PATCH] Expand LingeringPotion API - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -index e78eef3b6fbcd657f9dd180df4cb2eeb55d0814f..9d79b193fe2a737a20d1709548b2cd6c454ff27b 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -@@ -276,7 +276,7 @@ public class ThrownPotion extends ThrowableItemProjectile { - boolean noEffects = potioncontents.hasEffects(); // Paper - Fix potions splash events - // CraftBukkit start - org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, entityareaeffectcloud); -- if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (noEffects && !entityareaeffectcloud.potionContents.hasEffects()))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling -+ if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && !entityareaeffectcloud.potionContents.hasEffects())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling - this.level().addFreshEntity(entityareaeffectcloud); - } else { - entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause diff --git a/patches/server/0893-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch b/patches/server/0893-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch new file mode 100644 index 0000000000..ac9852081f --- /dev/null +++ b/patches/server/0893-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tamion <70228790+notTamion@users.noreply.github.com> +Date: Sat, 30 Sep 2023 12:36:14 +0200 +Subject: [PATCH] Fix strikeLightningEffect powers lightning rods and clears + copper + + +diff --git a/src/main/java/net/minecraft/world/entity/LightningBolt.java b/src/main/java/net/minecraft/world/entity/LightningBolt.java +index 152ecd38814089333b8d61538297ce720756d2c3..12127b14babf646711d3a118416453c4f1ac1460 100644 +--- a/src/main/java/net/minecraft/world/entity/LightningBolt.java ++++ b/src/main/java/net/minecraft/world/entity/LightningBolt.java +@@ -48,6 +48,7 @@ public class LightningBolt extends Entity { + private ServerPlayer cause; + private final Set hitEntities = Sets.newHashSet(); + private int blocksSetOnFire; ++ public boolean isEffect; // Paper - Properly handle lightning effects api + + public LightningBolt(EntityType type, Level world) { + super(type, world); +@@ -86,7 +87,7 @@ public class LightningBolt extends Entity { + @Override + public void tick() { + super.tick(); +- if (this.life == 2) { ++ if (!this.isEffect && this.life == 2) { // Paper - Properly handle lightning effects api + if (this.level().isClientSide()) { + this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_THUNDER, SoundSource.WEATHER, 10000.0F, 0.8F + this.random.nextFloat() * 0.2F, false); + this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_IMPACT, SoundSource.WEATHER, 2.0F, 0.5F + this.random.nextFloat() * 0.2F, false); +@@ -133,7 +134,7 @@ public class LightningBolt extends Entity { + } + } + +- if (this.life >= 0 && !this.visualOnly) { // CraftBukkit - add !this.visualOnly ++ if (this.life >= 0 && !this.isEffect) { // CraftBukkit - add !this.visualOnly // Paper - Properly handle lightning effects api + if (!(this.level() instanceof ServerLevel)) { + this.level().setSkyFlashTime(2); + } else if (!this.visualOnly) { +@@ -162,7 +163,7 @@ public class LightningBolt extends Entity { + } + + private void spawnFire(int spreadAttempts) { +- if (!this.visualOnly) { ++ if (!this.visualOnly && !this.isEffect) { // Paper - Properly handle lightning effects api + Level world = this.level(); + + if (world instanceof ServerLevel) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 041a6042a91f2a8933d7f9bcb44bb78894ffd405..b1ad6c47d3d42c93411753d4505ac9142b1697d3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -742,7 +742,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + LightningBolt lightning = EntityType.LIGHTNING_BOLT.create(this.world, EntitySpawnReason.COMMAND); + lightning.moveTo(loc.getX(), loc.getY(), loc.getZ()); +- lightning.setVisualOnly(isVisual); ++ lightning.isEffect = isVisual; // Paper - Properly handle lightning effects api + this.world.strikeLightning(lightning, LightningStrikeEvent.Cause.CUSTOM); + return (LightningStrike) lightning.getBukkitEntity(); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java +index 6fed8075aa75e3852dc826a45ca44603c0446a56..e9f471e60af0725ec34e2985d63ae9ea9f88590a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java +@@ -13,7 +13,7 @@ public class CraftLightningStrike extends CraftEntity implements LightningStrike + + @Override + public boolean isEffect() { +- return this.getHandle().visualOnly; ++ return this.getHandle().isEffect; // Paper - Properly handle lightning effects api + } + + public int getFlashes() { diff --git a/patches/server/0894-Add-hand-to-fish-event-for-all-player-interactions.patch b/patches/server/0894-Add-hand-to-fish-event-for-all-player-interactions.patch new file mode 100644 index 0000000000..cb3197a1b2 --- /dev/null +++ b/patches/server/0894-Add-hand-to-fish-event-for-all-player-interactions.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Mon, 3 Jul 2023 01:55:32 +0200 +Subject: [PATCH] Add hand to fish event for all player interactions + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java +index 1f95234c0a1457050574aa0f6c4b2a8c91b1f272..5b49b11d2d88b33731df582b119ef7a680d862e9 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java +@@ -487,7 +487,15 @@ public class FishingHook extends Projectile { + @Override + public void readAdditionalSaveData(CompoundTag nbt) {} + ++ // Paper start - Add hand parameter to PlayerFishEvent ++ @Deprecated ++ @io.papermc.paper.annotation.DoNotUse + public int retrieve(ItemStack usedItem) { ++ return this.retrieve(net.minecraft.world.InteractionHand.MAIN_HAND, usedItem); ++ } ++ ++ public int retrieve(net.minecraft.world.InteractionHand hand, ItemStack usedItem) { ++ // Paper end - Add hand parameter to PlayerFishEvent + net.minecraft.world.entity.player.Player entityhuman = this.getPlayerOwner(); + + if (!this.level().isClientSide && entityhuman != null && !this.shouldStopFishing(entityhuman)) { +@@ -495,7 +503,7 @@ public class FishingHook extends Projectile { + + if (this.hookedIn != null) { + // CraftBukkit start +- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_ENTITY); ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.CAUGHT_ENTITY); // Paper - Add hand parameter to PlayerFishEvent + this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); + + if (playerFishEvent.isCancelled()) { +@@ -524,7 +532,7 @@ public class FishingHook extends Projectile { + } + // Paper end + // CraftBukkit start +- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), entityitem != null ? entityitem.getBukkitEntity() : null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH); // Paper - entityitem may be null ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), entityitem != null ? entityitem.getBukkitEntity() : null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.CAUGHT_FISH); // Paper - entityitem may be null // Paper - Add hand parameter to PlayerFishEvent + playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1); + this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); + +@@ -558,7 +566,7 @@ public class FishingHook extends Projectile { + + if (this.onGround()) { + // CraftBukkit start +- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.IN_GROUND); ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.IN_GROUND); // Paper - Add hand parameter to PlayerFishEvent + this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); + + if (playerFishEvent.isCancelled()) { +@@ -569,7 +577,7 @@ public class FishingHook extends Projectile { + } + // CraftBukkit start + if (i == 0) { +- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.REEL_IN); ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.REEL_IN); // Paper - Add hand parameter to PlayerFishEvent + this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); + if (playerFishEvent.isCancelled()) { + return 0; +diff --git a/src/main/java/net/minecraft/world/item/FishingRodItem.java b/src/main/java/net/minecraft/world/item/FishingRodItem.java +index 5a50f3391d73fe881b8219d9da05c1dc45533251..801a513d67637136a15307a98fc6bbec9d202b00 100644 +--- a/src/main/java/net/minecraft/world/item/FishingRodItem.java ++++ b/src/main/java/net/minecraft/world/item/FishingRodItem.java +@@ -31,7 +31,7 @@ public class FishingRodItem extends Item { + + if (user.fishing != null) { + if (!world.isClientSide) { +- int i = user.fishing.retrieve(itemstack); ++ int i = user.fishing.retrieve(hand, itemstack); // Paper - Add hand parameter to PlayerFishEvent + + itemstack.hurtAndBreak(i, user, LivingEntity.getSlotForHand(hand)); + } diff --git a/patches/server/0894-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch b/patches/server/0894-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch deleted file mode 100644 index ac9852081f..0000000000 --- a/patches/server/0894-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tamion <70228790+notTamion@users.noreply.github.com> -Date: Sat, 30 Sep 2023 12:36:14 +0200 -Subject: [PATCH] Fix strikeLightningEffect powers lightning rods and clears - copper - - -diff --git a/src/main/java/net/minecraft/world/entity/LightningBolt.java b/src/main/java/net/minecraft/world/entity/LightningBolt.java -index 152ecd38814089333b8d61538297ce720756d2c3..12127b14babf646711d3a118416453c4f1ac1460 100644 ---- a/src/main/java/net/minecraft/world/entity/LightningBolt.java -+++ b/src/main/java/net/minecraft/world/entity/LightningBolt.java -@@ -48,6 +48,7 @@ public class LightningBolt extends Entity { - private ServerPlayer cause; - private final Set hitEntities = Sets.newHashSet(); - private int blocksSetOnFire; -+ public boolean isEffect; // Paper - Properly handle lightning effects api - - public LightningBolt(EntityType type, Level world) { - super(type, world); -@@ -86,7 +87,7 @@ public class LightningBolt extends Entity { - @Override - public void tick() { - super.tick(); -- if (this.life == 2) { -+ if (!this.isEffect && this.life == 2) { // Paper - Properly handle lightning effects api - if (this.level().isClientSide()) { - this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_THUNDER, SoundSource.WEATHER, 10000.0F, 0.8F + this.random.nextFloat() * 0.2F, false); - this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_IMPACT, SoundSource.WEATHER, 2.0F, 0.5F + this.random.nextFloat() * 0.2F, false); -@@ -133,7 +134,7 @@ public class LightningBolt extends Entity { - } - } - -- if (this.life >= 0 && !this.visualOnly) { // CraftBukkit - add !this.visualOnly -+ if (this.life >= 0 && !this.isEffect) { // CraftBukkit - add !this.visualOnly // Paper - Properly handle lightning effects api - if (!(this.level() instanceof ServerLevel)) { - this.level().setSkyFlashTime(2); - } else if (!this.visualOnly) { -@@ -162,7 +163,7 @@ public class LightningBolt extends Entity { - } - - private void spawnFire(int spreadAttempts) { -- if (!this.visualOnly) { -+ if (!this.visualOnly && !this.isEffect) { // Paper - Properly handle lightning effects api - Level world = this.level(); - - if (world instanceof ServerLevel) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 041a6042a91f2a8933d7f9bcb44bb78894ffd405..b1ad6c47d3d42c93411753d4505ac9142b1697d3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -742,7 +742,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - LightningBolt lightning = EntityType.LIGHTNING_BOLT.create(this.world, EntitySpawnReason.COMMAND); - lightning.moveTo(loc.getX(), loc.getY(), loc.getZ()); -- lightning.setVisualOnly(isVisual); -+ lightning.isEffect = isVisual; // Paper - Properly handle lightning effects api - this.world.strikeLightning(lightning, LightningStrikeEvent.Cause.CUSTOM); - return (LightningStrike) lightning.getBukkitEntity(); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java -index 6fed8075aa75e3852dc826a45ca44603c0446a56..e9f471e60af0725ec34e2985d63ae9ea9f88590a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java -@@ -13,7 +13,7 @@ public class CraftLightningStrike extends CraftEntity implements LightningStrike - - @Override - public boolean isEffect() { -- return this.getHandle().visualOnly; -+ return this.getHandle().isEffect; // Paper - Properly handle lightning effects api - } - - public int getFlashes() { diff --git a/patches/server/0895-Add-hand-to-fish-event-for-all-player-interactions.patch b/patches/server/0895-Add-hand-to-fish-event-for-all-player-interactions.patch deleted file mode 100644 index cb3197a1b2..0000000000 --- a/patches/server/0895-Add-hand-to-fish-event-for-all-player-interactions.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: booky10 -Date: Mon, 3 Jul 2023 01:55:32 +0200 -Subject: [PATCH] Add hand to fish event for all player interactions - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -index 1f95234c0a1457050574aa0f6c4b2a8c91b1f272..5b49b11d2d88b33731df582b119ef7a680d862e9 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -@@ -487,7 +487,15 @@ public class FishingHook extends Projectile { - @Override - public void readAdditionalSaveData(CompoundTag nbt) {} - -+ // Paper start - Add hand parameter to PlayerFishEvent -+ @Deprecated -+ @io.papermc.paper.annotation.DoNotUse - public int retrieve(ItemStack usedItem) { -+ return this.retrieve(net.minecraft.world.InteractionHand.MAIN_HAND, usedItem); -+ } -+ -+ public int retrieve(net.minecraft.world.InteractionHand hand, ItemStack usedItem) { -+ // Paper end - Add hand parameter to PlayerFishEvent - net.minecraft.world.entity.player.Player entityhuman = this.getPlayerOwner(); - - if (!this.level().isClientSide && entityhuman != null && !this.shouldStopFishing(entityhuman)) { -@@ -495,7 +503,7 @@ public class FishingHook extends Projectile { - - if (this.hookedIn != null) { - // CraftBukkit start -- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_ENTITY); -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.CAUGHT_ENTITY); // Paper - Add hand parameter to PlayerFishEvent - this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); - - if (playerFishEvent.isCancelled()) { -@@ -524,7 +532,7 @@ public class FishingHook extends Projectile { - } - // Paper end - // CraftBukkit start -- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), entityitem != null ? entityitem.getBukkitEntity() : null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH); // Paper - entityitem may be null -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), entityitem != null ? entityitem.getBukkitEntity() : null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.CAUGHT_FISH); // Paper - entityitem may be null // Paper - Add hand parameter to PlayerFishEvent - playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1); - this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); - -@@ -558,7 +566,7 @@ public class FishingHook extends Projectile { - - if (this.onGround()) { - // CraftBukkit start -- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.IN_GROUND); -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.IN_GROUND); // Paper - Add hand parameter to PlayerFishEvent - this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); - - if (playerFishEvent.isCancelled()) { -@@ -569,7 +577,7 @@ public class FishingHook extends Projectile { - } - // CraftBukkit start - if (i == 0) { -- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.REEL_IN); -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.REEL_IN); // Paper - Add hand parameter to PlayerFishEvent - this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); - if (playerFishEvent.isCancelled()) { - return 0; -diff --git a/src/main/java/net/minecraft/world/item/FishingRodItem.java b/src/main/java/net/minecraft/world/item/FishingRodItem.java -index 5a50f3391d73fe881b8219d9da05c1dc45533251..801a513d67637136a15307a98fc6bbec9d202b00 100644 ---- a/src/main/java/net/minecraft/world/item/FishingRodItem.java -+++ b/src/main/java/net/minecraft/world/item/FishingRodItem.java -@@ -31,7 +31,7 @@ public class FishingRodItem extends Item { - - if (user.fishing != null) { - if (!world.isClientSide) { -- int i = user.fishing.retrieve(itemstack); -+ int i = user.fishing.retrieve(hand, itemstack); // Paper - Add hand parameter to PlayerFishEvent - - itemstack.hurtAndBreak(i, user, LivingEntity.getSlotForHand(hand)); - } diff --git a/patches/server/0895-Fix-several-issues-with-EntityBreedEvent.patch b/patches/server/0895-Fix-several-issues-with-EntityBreedEvent.patch new file mode 100644 index 0000000000..7d7a988fc0 --- /dev/null +++ b/patches/server/0895-Fix-several-issues-with-EntityBreedEvent.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 15 Dec 2022 00:14:44 -0800 +Subject: [PATCH] Fix several issues with EntityBreedEvent + +Upstream did not account for different hands when storing +the breed item for later use in the event. Also they only +stored a reference to the stack, not a copy so if the stack +changed after love mode was started, the breed item in the event +also changed. Also in several places, the breed item was stored after +it was decreased by one to consume the item. + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java +index 775bfac26aaa6db998c2647ec81247b67d0bf784..5677dc97ed83652f261100cf391883cfac7d16fe 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Animal.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java +@@ -158,8 +158,9 @@ public abstract class Animal extends AgeableMob { + int i = this.getAge(); + + if (!this.level().isClientSide && i == 0 && this.canFallInLove()) { ++ final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying + this.usePlayerItem(player, hand, itemstack); +- this.setInLove(player); ++ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying + this.playEatingSound(); + return InteractionResult.SUCCESS_SERVER; + } +@@ -201,10 +202,18 @@ public abstract class Animal extends AgeableMob { + return this.inLove <= 0; + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Fix EntityBreedEvent copying + public void setInLove(@Nullable Player player) { ++ // Paper start - Fix EntityBreedEvent copying ++ this.setInLove(player, null); ++ } ++ public void setInLove(@Nullable Player player, @Nullable ItemStack breedItemCopy) { ++ if (breedItemCopy != null) this.breedItem = breedItemCopy; ++ // Paper end - Fix EntityBreedEvent copying + // CraftBukkit start + EntityEnterLoveModeEvent entityEnterLoveModeEvent = CraftEventFactory.callEntityEnterLoveModeEvent(player, this, 600); + if (entityEnterLoveModeEvent.isCancelled()) { ++ this.breedItem = null; // Paper - Fix EntityBreedEvent copying; clear if cancelled + return; + } + this.inLove = entityEnterLoveModeEvent.getTicksInLove(); +@@ -212,7 +221,7 @@ public abstract class Animal extends AgeableMob { + if (player != null) { + this.loveCause = player.getUUID(); + } +- this.breedItem = player.getInventory().getSelected(); // CraftBukkit ++ // Paper - Fix EntityBreedEvent copying; set breed item in better place + + this.level().broadcastEntityEvent(this, (byte) 18); + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java +index b654bec0fbe903fac24f3bb99399455bf367c68a..be753557d7ebd6f1e82b1bdb6d60ecc450f72eec 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java +@@ -653,8 +653,9 @@ public class Panda extends Animal { + this.usePlayerItem(player, hand, itemstack); + this.ageUp((int) ((float) (-this.getAge() / 20) * 0.1F), true); + } else if (!this.level().isClientSide && this.getAge() == 0 && this.canFallInLove()) { ++ final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying + this.usePlayerItem(player, hand, itemstack); +- this.setInLove(player); ++ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying + } else { + Level world = this.level(); + +diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java +index c99d37a40c63726c11980adccc67d09fd5132885..f3c884ab9c09f04dd01cabf2ee9de3b5b620563d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java ++++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java +@@ -395,7 +395,7 @@ public class Camel extends AbstractHorse { + boolean flag1 = this.isTamed() && this.getAge() == 0 && this.canFallInLove(); + + if (flag1) { +- this.setInLove(player); ++ this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying + } + + boolean flag2 = this.isBaby(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java +index 74151d69380e4adede40c7d7fc20834553706730..8aed30cdbbfdd42c20dcd4c8773c8a0ee21a980d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java +@@ -585,7 +585,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + b0 = 5; + if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { + flag = true; +- this.setInLove(player); ++ this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying + } + } else if (item.is(Items.GOLDEN_APPLE) || item.is(Items.ENCHANTED_GOLDEN_APPLE)) { + f = 10.0F; +@@ -593,7 +593,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + b0 = 10; + if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { + flag = true; +- this.setInLove(player); ++ this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying + } + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java +index 4da66867109394c8966e27551d20b4bcdf4bc9be..18bd483fe46de3d9dc129bffbccfba9d4cab9550 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java +@@ -177,7 +177,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder +Date: Thu, 9 Nov 2023 20:34:44 -0500 +Subject: [PATCH] Add UUID attribute modifier API + + +diff --git a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java +index 52439f4b959c74027eb191a3af960c70beb978e8..a2c057d92ea34368c7efc538b6e5b15ef342c54e 100644 +--- a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java ++++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java +@@ -5,6 +5,7 @@ import org.bukkit.attribute.Attribute; + import org.bukkit.attribute.AttributeModifier; + import org.bukkit.craftbukkit.attribute.CraftAttributeInstance; + ++import java.util.UUID; + import java.util.Collection; + + public class UnmodifiableAttributeInstance extends CraftAttributeInstance { +@@ -18,6 +19,11 @@ public class UnmodifiableAttributeInstance extends CraftAttributeInstance { + throw new UnsupportedOperationException("Cannot modify default attributes"); + } + ++ @Override ++ public void removeModifier(UUID uuid) { ++ throw new UnsupportedOperationException("Cannot modify default attributes"); ++ } ++ + @Override + public void addModifier(AttributeModifier modifier) { + throw new UnsupportedOperationException("Cannot modify default attributes"); +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/AttributeMappings.java b/src/main/java/org/bukkit/craftbukkit/attribute/AttributeMappings.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ce23ac9bcf5b043a07130da39cc8804f0d0be1e5 +--- /dev/null ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/AttributeMappings.java +@@ -0,0 +1,68 @@ ++package org.bukkit.craftbukkit.attribute; ++ ++import java.util.HashMap; ++import java.util.Map; ++import java.util.UUID; ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++final class AttributeMappings { ++ private static final Map ATTRIBUTE_MODIFIER_IDS = new HashMap<>(); ++ ++ static { ++ add(-4483571535397864886L, -5989644940537681742L, "armor.body"); ++ add(8144722948526719024L, -7778190119041365872L, "effect.slowness"); ++ add(6967552254039378640L, -9116175396973475259L, "enchantment.aqua_affinity"); ++ add(5279725409867744698L, -5150363631200102632L, "attacking"); ++ add(148071211714102867L, -7685811609035173472L, "attacking"); ++ add(6196088217904236654L, -7493791321850887290L, "effect.minining_fatigue"); ++ add(-5084161844451524480L, -8859020046251006329L, "enchantment.soul_speed"); ++ add(-7907339078496465106L, -8112074600724210224L, "enchantment.swift_sneak"); ++ add(6688265815086220243L, -6545541163342161890L, "drinking"); ++ add(8315164243412860989L, -6631520853640075966L, "creative_mode_block_range"); ++ add(4389663563256579765L, -4827163546944004714L, "enchantment.efficiency"); ++ add(6732612758648800940L, -5145707699103688244L, "effect.health_boost"); ++ add(9079981369298536661L, -6728494925450710401L, "covered"); ++ add(-1521481167610687786L, -8630419745734927691L, "effect.absorption"); ++ add(-7473408062188862076L, -5872005994337939597L, "creative_mode_entity_range"); ++ add(-3721396875562958315L, -5317020504214661337L, "effect.unluck"); ++ add(-2861585646493481178L, -6113244764726669811L, "armor.leggings"); ++ add(6718535547217657911L, -5386630269401489641L, "enchantment.sweeping_edge"); ++ add(-7949229004988660584L, -7828611303000832459L, "effect.speed"); ++ add(-8650171790042118250L, -5749650997644763080L, "enchantment.soul_speed"); ++ add(551224288813600377L, -8734740027710371860L, "enchantment.respiration"); ++ add(-7046399332347654691L, -6723081531683397260L, "suffocating"); ++ add(7361814797886573596L, -8641397326606817395L, "sprinting"); ++ add(-6972338111383059132L, -8978659762232839026L, "armor.chestplate"); ++ add(-5371971015925809039L, -6062243582569928137L, "enchantment.fire_protection"); ++ add(7245570952092733273L, -8449101711440750679L, "effect.strength"); ++ add(-422425648963762075L, -5756800103171642205L, "base_attack_speed"); ++ add(-4607081316629330256L, -7008565754814018370L, "effect.jump_boost"); ++ add(271280981090454338L, -8746077033958322898L, "effect.luck"); ++ add(2211131075215181206L, -5513857709499300658L, "powder_snow"); ++ add(-8908768238899017377L, -8313820693701227669L, "armor.boots"); ++ add(-5797418877589107702L, -6181652684028920077L, "effect.haste"); ++ add(3086076556416732775L, -5150312587563650736L, "armor.helmet"); ++ add(-5082757096938257406L, -4891139119377885130L, "baby"); ++ add(2478452629826324956L, -7247530463494186011L, "effect.weakness"); ++ add(4659420831966187055L, -5191473055587376048L, "enchantment.blast_protection"); ++ add(7301951777949303281L, -6753860660653972126L, "evil"); ++ add(8533189226688352746L, -8254757081029716377L, "baby"); ++ add(1286946037536540352L, -5768092872487507967L, "enchantment.depth_strider"); ++ add(-3801225194067177672L, -6586624321849018929L, "base_attack_damage"); ++ } ++ ++ public static @NotNull NamespacedKey uuidToKey(final UUID uuid) { ++ final NamespacedKey key = ATTRIBUTE_MODIFIER_IDS.get(uuid); ++ if (key != null) { ++ return key; ++ } else { ++ return NamespacedKey.minecraft(uuid.toString()); ++ } ++ } ++ ++ private static void add(final long msb, final long lsb, final String id) { ++ final UUID uuid = new UUID(msb, lsb); ++ ATTRIBUTE_MODIFIER_IDS.put(uuid, NamespacedKey.minecraft(id)); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java +index cd6a492f56b3dee5985c068e20009b6c833e143b..34b9d79fd1a4aa7395b3383fa721f5689494aa12 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java +@@ -45,6 +45,33 @@ public class CraftAttributeInstance implements AttributeInstance { + return result; + } + ++ // Paper start ++ @Override ++ public AttributeModifier getModifier(final net.kyori.adventure.key.Key key) { ++ Preconditions.checkArgument(key != null, "Key cannot be null"); ++ net.minecraft.world.entity.ai.attributes.AttributeModifier modifier = this.handle.getModifier(io.papermc.paper.adventure.PaperAdventure.asVanilla(key)); ++ return modifier == null ? null : CraftAttributeInstance.convert(modifier); ++ } ++ ++ @Override ++ public void removeModifier(final net.kyori.adventure.key.Key key) { ++ Preconditions.checkArgument(key != null, "Key cannot be null"); ++ this.handle.removeModifier(io.papermc.paper.adventure.PaperAdventure.asVanilla(key)); ++ } ++ ++ @Override ++ public AttributeModifier getModifier(java.util.UUID uuid) { ++ Preconditions.checkArgument(uuid != null, "UUID cannot be null"); ++ return this.getModifier(AttributeMappings.uuidToKey(uuid)); ++ } ++ ++ @Override ++ public void removeModifier(java.util.UUID uuid) { ++ Preconditions.checkArgument(uuid != null, "UUID cannot be null"); ++ this.removeModifier(AttributeMappings.uuidToKey(uuid)); ++ } ++ // Paper end ++ + @Override + public void addModifier(AttributeModifier modifier) { + Preconditions.checkArgument(modifier != null, "modifier"); diff --git a/patches/server/0896-Fix-several-issues-with-EntityBreedEvent.patch b/patches/server/0896-Fix-several-issues-with-EntityBreedEvent.patch deleted file mode 100644 index 7d7a988fc0..0000000000 --- a/patches/server/0896-Fix-several-issues-with-EntityBreedEvent.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 15 Dec 2022 00:14:44 -0800 -Subject: [PATCH] Fix several issues with EntityBreedEvent - -Upstream did not account for different hands when storing -the breed item for later use in the event. Also they only -stored a reference to the stack, not a copy so if the stack -changed after love mode was started, the breed item in the event -also changed. Also in several places, the breed item was stored after -it was decreased by one to consume the item. - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java -index 775bfac26aaa6db998c2647ec81247b67d0bf784..5677dc97ed83652f261100cf391883cfac7d16fe 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Animal.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java -@@ -158,8 +158,9 @@ public abstract class Animal extends AgeableMob { - int i = this.getAge(); - - if (!this.level().isClientSide && i == 0 && this.canFallInLove()) { -+ final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying - this.usePlayerItem(player, hand, itemstack); -- this.setInLove(player); -+ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying - this.playEatingSound(); - return InteractionResult.SUCCESS_SERVER; - } -@@ -201,10 +202,18 @@ public abstract class Animal extends AgeableMob { - return this.inLove <= 0; - } - -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Fix EntityBreedEvent copying - public void setInLove(@Nullable Player player) { -+ // Paper start - Fix EntityBreedEvent copying -+ this.setInLove(player, null); -+ } -+ public void setInLove(@Nullable Player player, @Nullable ItemStack breedItemCopy) { -+ if (breedItemCopy != null) this.breedItem = breedItemCopy; -+ // Paper end - Fix EntityBreedEvent copying - // CraftBukkit start - EntityEnterLoveModeEvent entityEnterLoveModeEvent = CraftEventFactory.callEntityEnterLoveModeEvent(player, this, 600); - if (entityEnterLoveModeEvent.isCancelled()) { -+ this.breedItem = null; // Paper - Fix EntityBreedEvent copying; clear if cancelled - return; - } - this.inLove = entityEnterLoveModeEvent.getTicksInLove(); -@@ -212,7 +221,7 @@ public abstract class Animal extends AgeableMob { - if (player != null) { - this.loveCause = player.getUUID(); - } -- this.breedItem = player.getInventory().getSelected(); // CraftBukkit -+ // Paper - Fix EntityBreedEvent copying; set breed item in better place - - this.level().broadcastEntityEvent(this, (byte) 18); - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java -index b654bec0fbe903fac24f3bb99399455bf367c68a..be753557d7ebd6f1e82b1bdb6d60ecc450f72eec 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Panda.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java -@@ -653,8 +653,9 @@ public class Panda extends Animal { - this.usePlayerItem(player, hand, itemstack); - this.ageUp((int) ((float) (-this.getAge() / 20) * 0.1F), true); - } else if (!this.level().isClientSide && this.getAge() == 0 && this.canFallInLove()) { -+ final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying - this.usePlayerItem(player, hand, itemstack); -- this.setInLove(player); -+ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying - } else { - Level world = this.level(); - -diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -index c99d37a40c63726c11980adccc67d09fd5132885..f3c884ab9c09f04dd01cabf2ee9de3b5b620563d 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -@@ -395,7 +395,7 @@ public class Camel extends AbstractHorse { - boolean flag1 = this.isTamed() && this.getAge() == 0 && this.canFallInLove(); - - if (flag1) { -- this.setInLove(player); -+ this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying - } - - boolean flag2 = this.isBaby(); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -index 74151d69380e4adede40c7d7fc20834553706730..8aed30cdbbfdd42c20dcd4c8773c8a0ee21a980d 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -@@ -585,7 +585,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - b0 = 5; - if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { - flag = true; -- this.setInLove(player); -+ this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying - } - } else if (item.is(Items.GOLDEN_APPLE) || item.is(Items.ENCHANTED_GOLDEN_APPLE)) { - f = 10.0F; -@@ -593,7 +593,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - b0 = 10; - if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { - flag = true; -- this.setInLove(player); -+ this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying - } - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 4da66867109394c8966e27551d20b4bcdf4bc9be..18bd483fe46de3d9dc129bffbccfba9d4cab9550 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -177,7 +177,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder -Date: Thu, 9 Nov 2023 20:34:44 -0500 -Subject: [PATCH] Add UUID attribute modifier API - - -diff --git a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -index 52439f4b959c74027eb191a3af960c70beb978e8..a2c057d92ea34368c7efc538b6e5b15ef342c54e 100644 ---- a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -+++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -@@ -5,6 +5,7 @@ import org.bukkit.attribute.Attribute; - import org.bukkit.attribute.AttributeModifier; - import org.bukkit.craftbukkit.attribute.CraftAttributeInstance; - -+import java.util.UUID; - import java.util.Collection; - - public class UnmodifiableAttributeInstance extends CraftAttributeInstance { -@@ -18,6 +19,11 @@ public class UnmodifiableAttributeInstance extends CraftAttributeInstance { - throw new UnsupportedOperationException("Cannot modify default attributes"); - } - -+ @Override -+ public void removeModifier(UUID uuid) { -+ throw new UnsupportedOperationException("Cannot modify default attributes"); -+ } -+ - @Override - public void addModifier(AttributeModifier modifier) { - throw new UnsupportedOperationException("Cannot modify default attributes"); -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/AttributeMappings.java b/src/main/java/org/bukkit/craftbukkit/attribute/AttributeMappings.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ce23ac9bcf5b043a07130da39cc8804f0d0be1e5 ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/AttributeMappings.java -@@ -0,0 +1,68 @@ -+package org.bukkit.craftbukkit.attribute; -+ -+import java.util.HashMap; -+import java.util.Map; -+import java.util.UUID; -+import org.bukkit.NamespacedKey; -+import org.jetbrains.annotations.NotNull; -+ -+final class AttributeMappings { -+ private static final Map ATTRIBUTE_MODIFIER_IDS = new HashMap<>(); -+ -+ static { -+ add(-4483571535397864886L, -5989644940537681742L, "armor.body"); -+ add(8144722948526719024L, -7778190119041365872L, "effect.slowness"); -+ add(6967552254039378640L, -9116175396973475259L, "enchantment.aqua_affinity"); -+ add(5279725409867744698L, -5150363631200102632L, "attacking"); -+ add(148071211714102867L, -7685811609035173472L, "attacking"); -+ add(6196088217904236654L, -7493791321850887290L, "effect.minining_fatigue"); -+ add(-5084161844451524480L, -8859020046251006329L, "enchantment.soul_speed"); -+ add(-7907339078496465106L, -8112074600724210224L, "enchantment.swift_sneak"); -+ add(6688265815086220243L, -6545541163342161890L, "drinking"); -+ add(8315164243412860989L, -6631520853640075966L, "creative_mode_block_range"); -+ add(4389663563256579765L, -4827163546944004714L, "enchantment.efficiency"); -+ add(6732612758648800940L, -5145707699103688244L, "effect.health_boost"); -+ add(9079981369298536661L, -6728494925450710401L, "covered"); -+ add(-1521481167610687786L, -8630419745734927691L, "effect.absorption"); -+ add(-7473408062188862076L, -5872005994337939597L, "creative_mode_entity_range"); -+ add(-3721396875562958315L, -5317020504214661337L, "effect.unluck"); -+ add(-2861585646493481178L, -6113244764726669811L, "armor.leggings"); -+ add(6718535547217657911L, -5386630269401489641L, "enchantment.sweeping_edge"); -+ add(-7949229004988660584L, -7828611303000832459L, "effect.speed"); -+ add(-8650171790042118250L, -5749650997644763080L, "enchantment.soul_speed"); -+ add(551224288813600377L, -8734740027710371860L, "enchantment.respiration"); -+ add(-7046399332347654691L, -6723081531683397260L, "suffocating"); -+ add(7361814797886573596L, -8641397326606817395L, "sprinting"); -+ add(-6972338111383059132L, -8978659762232839026L, "armor.chestplate"); -+ add(-5371971015925809039L, -6062243582569928137L, "enchantment.fire_protection"); -+ add(7245570952092733273L, -8449101711440750679L, "effect.strength"); -+ add(-422425648963762075L, -5756800103171642205L, "base_attack_speed"); -+ add(-4607081316629330256L, -7008565754814018370L, "effect.jump_boost"); -+ add(271280981090454338L, -8746077033958322898L, "effect.luck"); -+ add(2211131075215181206L, -5513857709499300658L, "powder_snow"); -+ add(-8908768238899017377L, -8313820693701227669L, "armor.boots"); -+ add(-5797418877589107702L, -6181652684028920077L, "effect.haste"); -+ add(3086076556416732775L, -5150312587563650736L, "armor.helmet"); -+ add(-5082757096938257406L, -4891139119377885130L, "baby"); -+ add(2478452629826324956L, -7247530463494186011L, "effect.weakness"); -+ add(4659420831966187055L, -5191473055587376048L, "enchantment.blast_protection"); -+ add(7301951777949303281L, -6753860660653972126L, "evil"); -+ add(8533189226688352746L, -8254757081029716377L, "baby"); -+ add(1286946037536540352L, -5768092872487507967L, "enchantment.depth_strider"); -+ add(-3801225194067177672L, -6586624321849018929L, "base_attack_damage"); -+ } -+ -+ public static @NotNull NamespacedKey uuidToKey(final UUID uuid) { -+ final NamespacedKey key = ATTRIBUTE_MODIFIER_IDS.get(uuid); -+ if (key != null) { -+ return key; -+ } else { -+ return NamespacedKey.minecraft(uuid.toString()); -+ } -+ } -+ -+ private static void add(final long msb, final long lsb, final String id) { -+ final UUID uuid = new UUID(msb, lsb); -+ ATTRIBUTE_MODIFIER_IDS.put(uuid, NamespacedKey.minecraft(id)); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -index cd6a492f56b3dee5985c068e20009b6c833e143b..34b9d79fd1a4aa7395b3383fa721f5689494aa12 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -@@ -45,6 +45,33 @@ public class CraftAttributeInstance implements AttributeInstance { - return result; - } - -+ // Paper start -+ @Override -+ public AttributeModifier getModifier(final net.kyori.adventure.key.Key key) { -+ Preconditions.checkArgument(key != null, "Key cannot be null"); -+ net.minecraft.world.entity.ai.attributes.AttributeModifier modifier = this.handle.getModifier(io.papermc.paper.adventure.PaperAdventure.asVanilla(key)); -+ return modifier == null ? null : CraftAttributeInstance.convert(modifier); -+ } -+ -+ @Override -+ public void removeModifier(final net.kyori.adventure.key.Key key) { -+ Preconditions.checkArgument(key != null, "Key cannot be null"); -+ this.handle.removeModifier(io.papermc.paper.adventure.PaperAdventure.asVanilla(key)); -+ } -+ -+ @Override -+ public AttributeModifier getModifier(java.util.UUID uuid) { -+ Preconditions.checkArgument(uuid != null, "UUID cannot be null"); -+ return this.getModifier(AttributeMappings.uuidToKey(uuid)); -+ } -+ -+ @Override -+ public void removeModifier(java.util.UUID uuid) { -+ Preconditions.checkArgument(uuid != null, "UUID cannot be null"); -+ this.removeModifier(AttributeMappings.uuidToKey(uuid)); -+ } -+ // Paper end -+ - @Override - public void addModifier(AttributeModifier modifier) { - Preconditions.checkArgument(modifier != null, "modifier"); diff --git a/patches/server/0897-Fix-missing-event-call-for-entity-teleport-API.patch b/patches/server/0897-Fix-missing-event-call-for-entity-teleport-API.patch new file mode 100644 index 0000000000..c00c1e49bd --- /dev/null +++ b/patches/server/0897-Fix-missing-event-call-for-entity-teleport-API.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Sun, 12 Nov 2023 05:09:47 +0100 +Subject: [PATCH] Fix missing event call for entity teleport API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 11a08ff211a9a32a825519ddb1736e02cf7f685e..7536ab5c22d97a074c08a95fff6bc756d61e387d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -259,6 +259,17 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return false; + } + ++ // Paper start - fix teleport event not being called ++ org.bukkit.event.entity.EntityTeleportEvent event = new org.bukkit.event.entity.EntityTeleportEvent( ++ this, this.getLocation(), location); ++ // cancelling the event is handled differently for players and entities, ++ // entities just stop teleporting, players will still teleport to the "from" location of the event ++ if (!event.callEvent() || event.getTo() == null) { ++ return false; ++ } ++ location = event.getTo(); ++ // Paper end ++ + // If this entity is riding another entity, we must dismount before teleporting. + if (dismount) this.entity.stopRiding(); // Paper - Teleport passenger API + diff --git a/patches/server/0898-Fix-missing-event-call-for-entity-teleport-API.patch b/patches/server/0898-Fix-missing-event-call-for-entity-teleport-API.patch deleted file mode 100644 index c00c1e49bd..0000000000 --- a/patches/server/0898-Fix-missing-event-call-for-entity-teleport-API.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: booky10 -Date: Sun, 12 Nov 2023 05:09:47 +0100 -Subject: [PATCH] Fix missing event call for entity teleport API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 11a08ff211a9a32a825519ddb1736e02cf7f685e..7536ab5c22d97a074c08a95fff6bc756d61e387d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -259,6 +259,17 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return false; - } - -+ // Paper start - fix teleport event not being called -+ org.bukkit.event.entity.EntityTeleportEvent event = new org.bukkit.event.entity.EntityTeleportEvent( -+ this, this.getLocation(), location); -+ // cancelling the event is handled differently for players and entities, -+ // entities just stop teleporting, players will still teleport to the "from" location of the event -+ if (!event.callEvent() || event.getTo() == null) { -+ return false; -+ } -+ location = event.getTo(); -+ // Paper end -+ - // If this entity is riding another entity, we must dismount before teleporting. - if (dismount) this.entity.stopRiding(); // Paper - Teleport passenger API - diff --git a/patches/server/0898-Lazily-create-LootContext-for-criterions.patch b/patches/server/0898-Lazily-create-LootContext-for-criterions.patch new file mode 100644 index 0000000000..d1033bf7e7 --- /dev/null +++ b/patches/server/0898-Lazily-create-LootContext-for-criterions.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrPowerGamerBR +Date: Tue, 21 Nov 2023 12:16:39 -0300 +Subject: [PATCH] Lazily create LootContext for criterions + +For each player on each tick, enter block triggers are invoked, and these create loot contexts that are promptly thrown away since the trigger doesn't pass the predicate + +To avoid this, we now lazily create the LootContext if the criterion passes the predicate AND if any of the listener triggers require a loot context instance + +diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java +index f43053ba082f9772b6ec02828fa2d6f387c32d26..35772110e9318df46a2729dbc0b5879b290011b7 100644 +--- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java ++++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java +@@ -42,14 +42,14 @@ public abstract class SimpleCriterionTrigger> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak + if (set != null && !set.isEmpty()) { +- LootContext lootContext = EntityPredicate.createContext(player, player); ++ LootContext lootContext = null; // EntityPredicate.createContext(player, player); // Paper - Perf: lazily create LootContext for criterions + List> list = null; + + for (CriterionTrigger.Listener listener : set) { + T simpleInstance = listener.trigger(); + if (predicate.test(simpleInstance)) { + Optional optional = simpleInstance.player(); +- if (optional.isEmpty() || optional.get().matches(lootContext)) { ++ if (optional.isEmpty() || optional.get().matches(lootContext = (lootContext == null ? EntityPredicate.createContext(player, player) : lootContext))) { // Paper - Perf: lazily create LootContext for criterions + if (list == null) { + list = Lists.newArrayList(); + } diff --git a/patches/server/0899-Don-t-fire-sync-events-during-worldgen.patch b/patches/server/0899-Don-t-fire-sync-events-during-worldgen.patch new file mode 100644 index 0000000000..f530a9f4e7 --- /dev/null +++ b/patches/server/0899-Don-t-fire-sync-events-during-worldgen.patch @@ -0,0 +1,208 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 23 Nov 2023 10:33:25 -0800 +Subject: [PATCH] Don't fire sync events during worldgen + +Fixes EntityPotionEffectEvent +Fixes EntityPoseChangeEvent + +Asynchronous chunk generation provides an opportunity for things +to happen async that previously fired synchronous-only events. This +patch is for mitigating those issues by various methods. + +Also fixes correctly marking/clearing the entity generation flag. +This patch sets the generation flag anytime an entity is created +via StructureTemplate before loading from NBT to catch uses of +the flag during the loading logic. This patch clears the generation +flag from an entity when added to a ServerLevel for the situation +where generation happened directly to a ServerLevel and the +entity still has the flag set. + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 7cecbac43f1cd2d9516034ea9d2633c0c76e61f4..7a985c30a973efacf3e8b70e7163c550d86b0870 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1189,6 +1189,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // CraftBukkit start + private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot ++ entity.generation = false; // Paper - Don't fire sync event during generation; Reset flag if it was added during a ServerLevel generation process + // Paper start - extra debug info + if (entity.valid) { + MinecraftServer.LOGGER.error("Attempted Double World add on {}", entity, new Throwable()); +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index c0539c8826a60cbe25855319cc174fb1520798c0..02b9d280486a23d8eef650566dfaa10ac0b96c9c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -631,7 +631,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (pose == this.getPose()) { + return; + } +- this.level.getCraftServer().getPluginManager().callEvent(new EntityPoseChangeEvent(this.getBukkitEntity(), Pose.values()[pose.ordinal()])); ++ // Paper start - Don't fire sync event during generation ++ if (!this.generation) { ++ this.level.getCraftServer().getPluginManager().callEvent(new EntityPoseChangeEvent(this.getBukkitEntity(), Pose.values()[pose.ordinal()])); ++ } ++ // Paper end - Don't fire sync event during generation + // CraftBukkit end + this.entityData.set(Entity.DATA_POSE, pose); + } +diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java +index 64dc0bd1900575e40ac72a98c6df371223bd244c..c2693d530be00af16b2aa4ca4afd1d136db68183 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -649,9 +649,15 @@ public class EntityType implements FeatureElement, EntityTypeT + } + + public static Optional create(CompoundTag nbt, Level world, EntitySpawnReason reason) { ++ // Paper start - Don't fire sync event during generation ++ return create(nbt, world, reason, false); ++ } ++ public static Optional create(CompoundTag nbt, Level world, EntitySpawnReason reason, boolean generation) { ++ // Paper end - Don't fire sync event during generation + return Util.ifElse(EntityType.by(nbt).map((entitytypes) -> { + return entitytypes.create(world, reason); + }), (entity) -> { ++ if (generation) entity.generation = true; // Paper - Don't fire sync event during generation + entity.load(nbt); + }, () -> { + EntityType.LOGGER.warn("Skipping Entity with id {}", nbt.getString("id")); +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 09bd6ba5907d42bed08872f18d40d8c743d392ff..251abe382f951c3ddac8112a0ffe1dc906b88e4c 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1159,6 +1159,11 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { ++ // Paper start - Don't fire sync event during generation ++ return this.addEffect(mobeffect, entity, cause, true); ++ } ++ public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) { ++ // Paper end - Don't fire sync event during generation + // org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot // Paper - move to API + if (this.isTickingEffects) { + this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); +@@ -1178,10 +1183,13 @@ public abstract class LivingEntity extends Entity implements Attackable { + override = new MobEffectInstance(mobeffect1).update(mobeffect); + } + ++ if (fireEvent) { // Paper - Don't fire sync event during generation + EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, mobeffect1, mobeffect, cause, override); ++ override = event.isOverride(); // Paper - Don't fire sync event during generation + if (event.isCancelled()) { + return false; + } ++ } // Paper - Don't fire sync event during generation + // CraftBukkit end + + if (mobeffect1 == null) { +@@ -1190,7 +1198,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + flag = true; + mobeffect.onEffectAdded(this); + // CraftBukkit start +- } else if (event.isOverride()) { ++ } else if (override) { // Paper - Don't fire sync event during generation + mobeffect1.update(mobeffect); + this.onEffectUpdated(mobeffect1, true, entity); + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java +index 6c2d4c2163cf299c0943af21d4dc367b5677c089..72e42605c278028480c368762da18f61806d766a 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Spider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java +@@ -172,7 +172,7 @@ public class Spider extends Monster { + Holder holder = entityspider_groupdataspider.effect; + + if (holder != null) { +- this.addEffect(new MobEffectInstance(holder, -1), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN); // CraftBukkit ++ this.addEffect(new MobEffectInstance(holder, -1), null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN, world instanceof net.minecraft.server.level.ServerLevel); // CraftBukkit + } + } + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +index 734f511d197bc6bf2b02588069eb02c0224781f5..d35b731751e851bee531aa5e7996557658ba6fae 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +@@ -549,7 +549,7 @@ public class StructureTemplate { + private static Optional createEntityIgnoreException(ServerLevelAccessor world, CompoundTag nbt) { + // CraftBukkit start + // try { +- return EntityType.create(nbt, world.getLevel(), EntitySpawnReason.STRUCTURE); ++ return EntityType.create(nbt, world.getLevel(), EntitySpawnReason.STRUCTURE, true); // Paper - Don't fire sync event during generation + // } catch (Exception exception) { + // return Optional.empty(); + // } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +index e444662ee4d9405eeea7caa41b9cd6b36586d840..54c4434662d057a08800918641b95708cda61207 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +@@ -90,15 +90,17 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { + return this.handle.getLevel(); + } + +- @Override +- public void addFreshEntityWithPassengers(Entity entity) { +- this.handle.addFreshEntityWithPassengers(entity); +- } +- +- @Override +- public void addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason) { +- this.handle.addFreshEntityWithPassengers(entity, reason); +- } ++ // Paper start - Don't fire sync event during generation; don't override these methods so all entities are run through addFreshEntity ++ // @Override ++ // public void addFreshEntityWithPassengers(Entity entity) { ++ // this.handle.addFreshEntityWithPassengers(entity); ++ // } ++ // ++ // @Override ++ // public void addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason) { ++ // this.handle.addFreshEntityWithPassengers(entity, reason); ++ // } ++ // Paper end - Don't fire sync event during generation; don't override these methods so all entities are run through addFreshEntity + + @Override + public ServerLevel getMinecraftWorld() { +diff --git a/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java +index 35ecf6f824aca56a20280dd683123df1d0c7d66e..1d1fdcf10498c421f106158254e052da6d68d8a5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java +@@ -39,21 +39,23 @@ public class TransformerGeneratorAccess extends DelegatedGeneratorAccess { + return super.addFreshEntity(arg0, arg1); + } + +- @Override +- public void addFreshEntityWithPassengers(Entity entity) { +- if (this.structureTransformer != null && !this.structureTransformer.transformEntity(entity)) { +- return; +- } +- super.addFreshEntityWithPassengers(entity); +- } +- +- @Override +- public void addFreshEntityWithPassengers(Entity arg0, SpawnReason arg1) { +- if (this.structureTransformer != null && !this.structureTransformer.transformEntity(arg0)) { +- return; +- } +- super.addFreshEntityWithPassengers(arg0, arg1); +- } ++ // Paper start - Don't fire sync event during generation; don't override these methods so all entities are run through addFreshEntity ++ // @Override ++ // public void addFreshEntityWithPassengers(Entity entity) { ++ // if (this.structureTransformer != null && !this.structureTransformer.transformEntity(entity)) { ++ // return; ++ // } ++ // super.addFreshEntityWithPassengers(entity); ++ // } ++ // ++ // @Override ++ // public void addFreshEntityWithPassengers(Entity arg0, SpawnReason arg1) { ++ // if (this.structureTransformer != null && !this.structureTransformer.transformEntity(arg0)) { ++ // return; ++ // } ++ // super.addFreshEntityWithPassengers(arg0, arg1); ++ // } ++ // Paper end - Don't fire sync event during generation; don't override these methods + + public boolean setCraftBlock(BlockPos position, CraftBlockState craftBlockState, int i, int j) { + if (this.structureTransformer != null) { diff --git a/patches/server/0899-Lazily-create-LootContext-for-criterions.patch b/patches/server/0899-Lazily-create-LootContext-for-criterions.patch deleted file mode 100644 index d1033bf7e7..0000000000 --- a/patches/server/0899-Lazily-create-LootContext-for-criterions.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrPowerGamerBR -Date: Tue, 21 Nov 2023 12:16:39 -0300 -Subject: [PATCH] Lazily create LootContext for criterions - -For each player on each tick, enter block triggers are invoked, and these create loot contexts that are promptly thrown away since the trigger doesn't pass the predicate - -To avoid this, we now lazily create the LootContext if the criterion passes the predicate AND if any of the listener triggers require a loot context instance - -diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -index f43053ba082f9772b6ec02828fa2d6f387c32d26..35772110e9318df46a2729dbc0b5879b290011b7 100644 ---- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -+++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -@@ -42,14 +42,14 @@ public abstract class SimpleCriterionTrigger> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak - if (set != null && !set.isEmpty()) { -- LootContext lootContext = EntityPredicate.createContext(player, player); -+ LootContext lootContext = null; // EntityPredicate.createContext(player, player); // Paper - Perf: lazily create LootContext for criterions - List> list = null; - - for (CriterionTrigger.Listener listener : set) { - T simpleInstance = listener.trigger(); - if (predicate.test(simpleInstance)) { - Optional optional = simpleInstance.player(); -- if (optional.isEmpty() || optional.get().matches(lootContext)) { -+ if (optional.isEmpty() || optional.get().matches(lootContext = (lootContext == null ? EntityPredicate.createContext(player, player) : lootContext))) { // Paper - Perf: lazily create LootContext for criterions - if (list == null) { - list = Lists.newArrayList(); - } diff --git a/patches/server/0900-Add-Structure-check-API.patch b/patches/server/0900-Add-Structure-check-API.patch new file mode 100644 index 0000000000..d138a01f44 --- /dev/null +++ b/patches/server/0900-Add-Structure-check-API.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 27 Mar 2023 10:20:00 -0700 +Subject: [PATCH] Add Structure check API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index b1ad6c47d3d42c93411753d4505ac9142b1697d3..34e8afae13085f0a9ce0c916d911c88c395418e0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -250,6 +250,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { + }; + } + // Paper end ++ // Paper start - structure check API ++ @Override ++ public boolean hasStructureAt(final io.papermc.paper.math.Position position, final Structure structure) { ++ return this.world.structureManager().getStructureWithPieceAt( ++ io.papermc.paper.util.MCUtil.toBlockPos(position), ++ CraftStructure.bukkitToMinecraft(structure) ++ ).isValid(); ++ } ++ // Paper end + + private static final Random rand = new Random(); + diff --git a/patches/server/0900-Don-t-fire-sync-events-during-worldgen.patch b/patches/server/0900-Don-t-fire-sync-events-during-worldgen.patch deleted file mode 100644 index 389d1d5fde..0000000000 --- a/patches/server/0900-Don-t-fire-sync-events-during-worldgen.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 23 Nov 2023 10:33:25 -0800 -Subject: [PATCH] Don't fire sync events during worldgen - -Fixes EntityPotionEffectEvent -Fixes EntityPoseChangeEvent - -Asynchronous chunk generation provides an opportunity for things -to happen async that previously fired synchronous-only events. This -patch is for mitigating those issues by various methods. - -Also fixes correctly marking/clearing the entity generation flag. -This patch sets the generation flag anytime an entity is created -via StructureTemplate before loading from NBT to catch uses of -the flag during the loading logic. This patch clears the generation -flag from an entity when added to a ServerLevel for the situation -where generation happened directly to a ServerLevel and the -entity still has the flag set. - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 1bacbb0d0bd5198d0f946a959b2335d6fba0ca88..a628da8a0ed7ae2c7b46df3881bd75dc5b4fd607 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1219,6 +1219,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // CraftBukkit start - private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { - org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot -+ entity.generation = false; // Paper - Don't fire sync event during generation; Reset flag if it was added during a ServerLevel generation process - // Paper start - extra debug info - if (entity.valid) { - MinecraftServer.LOGGER.error("Attempted Double World add on {}", entity, new Throwable()); -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index c0539c8826a60cbe25855319cc174fb1520798c0..02b9d280486a23d8eef650566dfaa10ac0b96c9c 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -631,7 +631,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (pose == this.getPose()) { - return; - } -- this.level.getCraftServer().getPluginManager().callEvent(new EntityPoseChangeEvent(this.getBukkitEntity(), Pose.values()[pose.ordinal()])); -+ // Paper start - Don't fire sync event during generation -+ if (!this.generation) { -+ this.level.getCraftServer().getPluginManager().callEvent(new EntityPoseChangeEvent(this.getBukkitEntity(), Pose.values()[pose.ordinal()])); -+ } -+ // Paper end - Don't fire sync event during generation - // CraftBukkit end - this.entityData.set(Entity.DATA_POSE, pose); - } -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index ca9e63942f3cb8986456410b2a77aafc6541aad2..ccee69813597f45d382268bd1792a49722afebe9 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -658,9 +658,15 @@ public class EntityType implements FeatureElement, EntityTypeT - } - - public static Optional create(CompoundTag nbt, Level world, EntitySpawnReason reason) { -+ // Paper start - Don't fire sync event during generation -+ return create(nbt, world, reason, false); -+ } -+ public static Optional create(CompoundTag nbt, Level world, EntitySpawnReason reason, boolean generation) { -+ // Paper end - Don't fire sync event during generation - return Util.ifElse(EntityType.by(nbt).map((entitytypes) -> { - return entitytypes.create(world, reason); - }), (entity) -> { -+ if (generation) entity.generation = true; // Paper - Don't fire sync event during generation - entity.load(nbt); - }, () -> { - EntityType.LOGGER.warn("Skipping Entity with id {}", nbt.getString("id")); -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 30424789ba1c8d25f830145501b4a7399b91f2d1..9bc6ed9fd8e5154d39fe12ffed1ecd5ec8e70df8 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1161,6 +1161,11 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { -+ // Paper start - Don't fire sync event during generation -+ return this.addEffect(mobeffect, entity, cause, true); -+ } -+ public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) { -+ // Paper end - Don't fire sync event during generation - // org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot // Paper - move to API - if (this.isTickingEffects) { - this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); -@@ -1180,10 +1185,13 @@ public abstract class LivingEntity extends Entity implements Attackable { - override = new MobEffectInstance(mobeffect1).update(mobeffect); - } - -+ if (fireEvent) { // Paper - Don't fire sync event during generation - EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, mobeffect1, mobeffect, cause, override); -+ override = event.isOverride(); // Paper - Don't fire sync event during generation - if (event.isCancelled()) { - return false; - } -+ } // Paper - Don't fire sync event during generation - // CraftBukkit end - - if (mobeffect1 == null) { -@@ -1192,7 +1200,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - flag = true; - mobeffect.onEffectAdded(this); - // CraftBukkit start -- } else if (event.isOverride()) { -+ } else if (override) { // Paper - Don't fire sync event during generation - mobeffect1.update(mobeffect); - this.onEffectUpdated(mobeffect1, true, entity); - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java -index 6c2d4c2163cf299c0943af21d4dc367b5677c089..72e42605c278028480c368762da18f61806d766a 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Spider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java -@@ -172,7 +172,7 @@ public class Spider extends Monster { - Holder holder = entityspider_groupdataspider.effect; - - if (holder != null) { -- this.addEffect(new MobEffectInstance(holder, -1), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN); // CraftBukkit -+ this.addEffect(new MobEffectInstance(holder, -1), null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN, world instanceof net.minecraft.server.level.ServerLevel); // CraftBukkit - } - } - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -index 734f511d197bc6bf2b02588069eb02c0224781f5..d35b731751e851bee531aa5e7996557658ba6fae 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -@@ -549,7 +549,7 @@ public class StructureTemplate { - private static Optional createEntityIgnoreException(ServerLevelAccessor world, CompoundTag nbt) { - // CraftBukkit start - // try { -- return EntityType.create(nbt, world.getLevel(), EntitySpawnReason.STRUCTURE); -+ return EntityType.create(nbt, world.getLevel(), EntitySpawnReason.STRUCTURE, true); // Paper - Don't fire sync event during generation - // } catch (Exception exception) { - // return Optional.empty(); - // } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index e444662ee4d9405eeea7caa41b9cd6b36586d840..54c4434662d057a08800918641b95708cda61207 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -@@ -90,15 +90,17 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { - return this.handle.getLevel(); - } - -- @Override -- public void addFreshEntityWithPassengers(Entity entity) { -- this.handle.addFreshEntityWithPassengers(entity); -- } -- -- @Override -- public void addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason) { -- this.handle.addFreshEntityWithPassengers(entity, reason); -- } -+ // Paper start - Don't fire sync event during generation; don't override these methods so all entities are run through addFreshEntity -+ // @Override -+ // public void addFreshEntityWithPassengers(Entity entity) { -+ // this.handle.addFreshEntityWithPassengers(entity); -+ // } -+ // -+ // @Override -+ // public void addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason) { -+ // this.handle.addFreshEntityWithPassengers(entity, reason); -+ // } -+ // Paper end - Don't fire sync event during generation; don't override these methods so all entities are run through addFreshEntity - - @Override - public ServerLevel getMinecraftWorld() { -diff --git a/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java -index 35ecf6f824aca56a20280dd683123df1d0c7d66e..1d1fdcf10498c421f106158254e052da6d68d8a5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java -@@ -39,21 +39,23 @@ public class TransformerGeneratorAccess extends DelegatedGeneratorAccess { - return super.addFreshEntity(arg0, arg1); - } - -- @Override -- public void addFreshEntityWithPassengers(Entity entity) { -- if (this.structureTransformer != null && !this.structureTransformer.transformEntity(entity)) { -- return; -- } -- super.addFreshEntityWithPassengers(entity); -- } -- -- @Override -- public void addFreshEntityWithPassengers(Entity arg0, SpawnReason arg1) { -- if (this.structureTransformer != null && !this.structureTransformer.transformEntity(arg0)) { -- return; -- } -- super.addFreshEntityWithPassengers(arg0, arg1); -- } -+ // Paper start - Don't fire sync event during generation; don't override these methods so all entities are run through addFreshEntity -+ // @Override -+ // public void addFreshEntityWithPassengers(Entity entity) { -+ // if (this.structureTransformer != null && !this.structureTransformer.transformEntity(entity)) { -+ // return; -+ // } -+ // super.addFreshEntityWithPassengers(entity); -+ // } -+ // -+ // @Override -+ // public void addFreshEntityWithPassengers(Entity arg0, SpawnReason arg1) { -+ // if (this.structureTransformer != null && !this.structureTransformer.transformEntity(arg0)) { -+ // return; -+ // } -+ // super.addFreshEntityWithPassengers(arg0, arg1); -+ // } -+ // Paper end - Don't fire sync event during generation; don't override these methods - - public boolean setCraftBlock(BlockPos position, CraftBlockState craftBlockState, int i, int j) { - if (this.structureTransformer != null) { diff --git a/patches/server/0901-Add-Structure-check-API.patch b/patches/server/0901-Add-Structure-check-API.patch deleted file mode 100644 index d138a01f44..0000000000 --- a/patches/server/0901-Add-Structure-check-API.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 27 Mar 2023 10:20:00 -0700 -Subject: [PATCH] Add Structure check API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index b1ad6c47d3d42c93411753d4505ac9142b1697d3..34e8afae13085f0a9ce0c916d911c88c395418e0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -250,6 +250,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { - }; - } - // Paper end -+ // Paper start - structure check API -+ @Override -+ public boolean hasStructureAt(final io.papermc.paper.math.Position position, final Structure structure) { -+ return this.world.structureManager().getStructureWithPieceAt( -+ io.papermc.paper.util.MCUtil.toBlockPos(position), -+ CraftStructure.bukkitToMinecraft(structure) -+ ).isValid(); -+ } -+ // Paper end - - private static final Random rand = new Random(); - diff --git a/patches/server/0901-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch b/patches/server/0901-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch new file mode 100644 index 0000000000..db45e464ac --- /dev/null +++ b/patches/server/0901-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hyper1423 +Date: Sun, 3 Dec 2023 07:38:09 +0900 +Subject: [PATCH] Fix CraftMetaItem#getAttributeModifier duplication check + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index af78e73755743fb2db7a99b834affc963b44bc10..3bcc807005a677884255f1ee36cbf1653797ba55 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -1666,7 +1666,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + Preconditions.checkNotNull(modifier, "AttributeModifier cannot be null"); + this.checkAttributeList(); + for (Map.Entry entry : this.attributeModifiers.entries()) { +- Preconditions.checkArgument(!entry.getValue().getKey().equals(modifier.getKey()), "Cannot register AttributeModifier. Modifier is already applied! %s", modifier); ++ Preconditions.checkArgument(!(entry.getValue().getKey().equals(modifier.getKey()) && entry.getKey() == attribute), "Cannot register AttributeModifier. Modifier is already applied! %s", modifier); // Paper - attribute modifiers with same namespaced key but on different attributes are fine + } + return this.attributeModifiers.put(attribute, modifier); + } diff --git a/patches/server/0902-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch b/patches/server/0902-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch deleted file mode 100644 index db45e464ac..0000000000 --- a/patches/server/0902-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: hyper1423 -Date: Sun, 3 Dec 2023 07:38:09 +0900 -Subject: [PATCH] Fix CraftMetaItem#getAttributeModifier duplication check - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index af78e73755743fb2db7a99b834affc963b44bc10..3bcc807005a677884255f1ee36cbf1653797ba55 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -1666,7 +1666,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - Preconditions.checkNotNull(modifier, "AttributeModifier cannot be null"); - this.checkAttributeList(); - for (Map.Entry entry : this.attributeModifiers.entries()) { -- Preconditions.checkArgument(!entry.getValue().getKey().equals(modifier.getKey()), "Cannot register AttributeModifier. Modifier is already applied! %s", modifier); -+ Preconditions.checkArgument(!(entry.getValue().getKey().equals(modifier.getKey()) && entry.getKey() == attribute), "Cannot register AttributeModifier. Modifier is already applied! %s", modifier); // Paper - attribute modifiers with same namespaced key but on different attributes are fine - } - return this.attributeModifiers.put(attribute, modifier); - } diff --git a/patches/server/0902-Restore-vanilla-entity-drops-behavior.patch b/patches/server/0902-Restore-vanilla-entity-drops-behavior.patch new file mode 100644 index 0000000000..c19f1327f4 --- /dev/null +++ b/patches/server/0902-Restore-vanilla-entity-drops-behavior.patch @@ -0,0 +1,269 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 22 Mar 2022 09:34:41 -0700 +Subject: [PATCH] Restore vanilla entity drops behavior + +Instead of just tracking the itemstacks, this tracks with it, the +action to take with that itemstack to apply the correct logic +on dropping the item instead of generalizing it for all dropped +items like CB does. + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 419fcb4cd97cf10a2601e02024b999a51a0ff952..df21cd1bd2a3dda7169edbea18bbfdf043db76f8 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1235,20 +1235,20 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + if (this.isRemoved()) { + return; + } +- java.util.List loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); ++ List loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper - Restore vanilla drops behavior + boolean keepInventory = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator(); + + if (!keepInventory) { + for (ItemStack item : this.getInventory().getContents()) { + if (!item.isEmpty() && !EnchantmentHelper.has(item, EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) { +- loot.add(CraftItemStack.asCraftMirror(item).markForInventoryDrop()); ++ loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event) + } + } + } + if (this.shouldDropLoot() && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false + // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule) + this.dropFromLootTable(this.serverLevel(), damageSource, this.lastHurtByPlayerTime > 0); +- this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag); ++ // Paper - Restore vanilla drops behaviour; custom death loot is a noop on server player, remove. + + loot.addAll(this.drops); + this.drops.clear(); // SPIGOT-5188: make sure to clear +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 02b9d280486a23d8eef650566dfaa10ac0b96c9c..cdc5ea3dd9559c076049c86a9fdb4e8bf85ff6c0 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2678,19 +2678,45 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + @Nullable + public ItemEntity spawnAtLocation(ServerLevel world, ItemStack stack, float yOffset) { ++ // Paper start - Restore vanilla drops behavior ++ return this.spawnAtLocation(world, stack, yOffset, null); ++ } ++ public record DefaultDrop(Item item, org.bukkit.inventory.ItemStack stack, @Nullable java.util.function.Consumer dropConsumer) { ++ public DefaultDrop(final ItemStack stack, final java.util.function.Consumer dropConsumer) { ++ this(stack.getItem(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), dropConsumer); ++ } ++ ++ public void runConsumer(final java.util.function.Consumer fallback) { ++ if (this.dropConsumer == null || org.bukkit.craftbukkit.inventory.CraftItemType.bukkitToMinecraft(this.stack.getType()) != this.item) { ++ fallback.accept(this.stack); ++ } else { ++ this.dropConsumer.accept(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(this.stack)); ++ } ++ } ++ } ++ @Nullable ++ public ItemEntity spawnAtLocation(ServerLevel world, ItemStack stack, float yOffset, @Nullable java.util.function.Consumer delayedAddConsumer) { ++ // Paper end - Restore vanilla drops behavior + if (stack.isEmpty()) { + return null; + } else { + // CraftBukkit start - Capture drops for death event + if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) { +- ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later ++ // Paper start - Restore vanilla drops behavior ++ ((net.minecraft.world.entity.LivingEntity) this).drops.add(new net.minecraft.world.entity.Entity.DefaultDrop(stack, itemStack -> { ++ ItemEntity itemEntity = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), itemStack); // stack is copied before consumer ++ itemEntity.setDefaultPickUpDelay(); ++ this.level.addFreshEntity(itemEntity); ++ if (delayedAddConsumer != null) delayedAddConsumer.accept(itemEntity); ++ })); ++ // Paper end - Restore vanilla drops behavior + return null; + } + // CraftBukkit end + ItemEntity entityitem = new ItemEntity(world, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - copy so we can destroy original + stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe + +- entityitem.setDefaultPickUpDelay(); ++ entityitem.setDefaultPickUpDelay(); // Paper - diff on change (in dropConsumer) + // Paper start - Call EntityDropItemEvent + return this.spawnAtLocation(world, entityitem); + } +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 251abe382f951c3ddac8112a0ffe1dc906b88e4c..adde7352cdbcb8684f43d6bf5978b6943e9f165b 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -289,7 +289,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + protected float appliedScale; + // CraftBukkit start + public int expToDrop; +- public ArrayList drops = new ArrayList(); ++ public ArrayList drops = new ArrayList<>(); // Paper - Restore vanilla drops behavior + public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes; + public boolean collides = true; + public Set collidableExemptions = new HashSet<>(); +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +index e6b18d7f8922cb42acb9e40bef2f71a56aea8646..e1be143959fbaa1d54af2a1a2c27187d70e6a9e9 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -536,10 +536,10 @@ public class WitherBoss extends Monster implements RangedAttackMob { + @Override + protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) { + super.dropCustomDeathLoot(world, source, causedByPlayer); +- ItemEntity entityitem = this.spawnAtLocation(world, (ItemLike) Items.NETHER_STAR); ++ ItemEntity entityitem = this.spawnAtLocation(world, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer + + if (entityitem != null) { +- entityitem.setExtendedLifetime(); ++ entityitem.setExtendedLifetime(); // Paper - diff on change + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +index 2bb2b36f793d25b6e49d1a72bb665cfa9f212730..63f02cdc67d9e88cc6998d0ae9d139c83e85b447 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +@@ -619,7 +619,7 @@ public class ArmorStand extends LivingEntity { + ItemStack itemstack = new ItemStack(Items.ARMOR_STAND); + + itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); +- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops ++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior + return this.brokenByAnything(world, damageSource); // Paper + } + +@@ -633,7 +633,7 @@ public class ArmorStand extends LivingEntity { + for (i = 0; i < this.handItems.size(); ++i) { + itemstack = (ItemStack) this.handItems.get(i); + if (!itemstack.isEmpty()) { +- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe ++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly + this.handItems.set(i, ItemStack.EMPTY); + } + } +@@ -641,7 +641,7 @@ public class ArmorStand extends LivingEntity { + for (i = 0; i < this.armorItems.size(); ++i) { + itemstack = (ItemStack) this.armorItems.get(i); + if (!itemstack.isEmpty()) { +- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe ++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly + this.armorItems.set(i, ItemStack.EMPTY); + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index dbef230ae88ee1bfbc20ba53b534434c3ccac985..a0455f590d549343d6d8fd7991ba1b87a87acdb8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -973,19 +973,25 @@ public class CraftEventFactory { + } + + public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource) { +- return CraftEventFactory.callEntityDeathEvent(victim, damageSource, new ArrayList(0)); ++ return CraftEventFactory.callEntityDeathEvent(victim, damageSource, new ArrayList<>(0)); // Paper - Restore vanilla drops behavior + } + +- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops) { ++ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops) { // Paper - Restore vanilla drops behavior + // Paper start + return CraftEventFactory.callEntityDeathEvent(victim, damageSource, drops, com.google.common.util.concurrent.Runnables.doNothing()); + } +- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops, Runnable lootCheck) { ++ ++ private static final java.util.function.Function FROM_FUNCTION = stack -> { ++ if (stack == null) return null; ++ return new Entity.DefaultDrop(CraftItemType.bukkitToMinecraft(stack.getType()), stack, null); ++ }; ++ ++ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops, Runnable lootCheck) { // Paper - Restore vanilla drops behavior + // Paper end + CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity(); + CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource); + CraftWorld world = (CraftWorld) entity.getWorld(); +- EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(world.getHandle(), damageSource.getEntity())); ++ EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(world.getHandle(), damageSource.getEntity())); // Paper - Restore vanilla drops behavior + populateFields(victim, event); // Paper - make cancellable + Bukkit.getServer().getPluginManager().callEvent(event); + +@@ -998,20 +1004,24 @@ public class CraftEventFactory { + victim.expToDrop = event.getDroppedExp(); + lootCheck.run(); // Paper - advancement triggers before destroying items + +- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { ++ // Paper start - Restore vanilla drops behavior ++ for (Entity.DefaultDrop drop : drops) { ++ if (drop == null) continue; ++ final org.bukkit.inventory.ItemStack stack = drop.stack(); ++ // Paper end - Restore vanilla drops behavior + if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue; + +- world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS ++ drop.runConsumer(s -> world.dropItem(entity.getLocation(), s)); // Paper - Restore vanilla drops behavior + if (stack instanceof CraftItemStack) stack.setAmount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe, but don't nuke bukkit stacks of manually added items + } + + return event; + } + +- public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, DamageSource damageSource, List drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure ++ public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, DamageSource damageSource, List drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure & Restore vanilla drops behavior + CraftPlayer entity = victim.getBukkitEntity(); + CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource); +- PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(victim.serverLevel(), damageSource.getEntity()), 0, deathMessage); ++ PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(victim.serverLevel(), damageSource.getEntity()), 0, deathMessage); // Paper - Restore vanilla drops behavior + event.setKeepInventory(keepInventory); + event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel + populateFields(victim, event); // Paper - make cancellable +@@ -1029,16 +1039,14 @@ public class CraftEventFactory { + victim.expToDrop = event.getDroppedExp(); + victim.newExp = event.getNewExp(); + +- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { ++ // Paper start - Restore vanilla drops behavior ++ for (Entity.DefaultDrop drop : drops) { ++ if (drop == null) continue; ++ final org.bukkit.inventory.ItemStack stack = drop.stack(); ++ // Paper end - Restore vanilla drops behavior + if (stack == null || stack.getType() == Material.AIR) continue; + +- if (stack instanceof CraftItemStack craftItemStack && craftItemStack.isForInventoryDrop()) { +- victim.drop(CraftItemStack.asNMSCopy(stack), true, false, false); // SPIGOT-7800, SPIGOT-7801: Vanilla Behaviour for Player Inventory dropped items +- } else { +- victim.forceDrops = true; +- victim.spawnAtLocation(victim.serverLevel(), CraftItemStack.asNMSCopy(stack)); // SPIGOT-7806: Vanilla Behaviour for items not related to Player Inventory dropped items +- victim.forceDrops = false; +- } ++ drop.runConsumer(s -> victim.drop(CraftItemStack.unwrap(s), true, false, false)); // Paper - Restore vanilla drops behavior + } + + return event; +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 30eba68435387daa3917fa2b3071892c350d9ddc..0b7bc5e83634a26ac6521694377b554c74c6bff0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -142,27 +142,6 @@ public final class CraftItemStack extends ItemStack { + this.setItemMeta(itemMeta); + } + +- /** +- * Gets if the item is marked as an inventory drop in death events. +- * +- * @return true if the item is marked as an inventory drop +- */ +- @ApiStatus.Internal +- public boolean isForInventoryDrop() { +- return this.isForInventoryDrop; +- } +- +- /** +- * Marks this item as an inventory drop in death events. +- * +- * @return the ItemStack marked as an inventory drop +- */ +- @ApiStatus.Internal +- public ItemStack markForInventoryDrop() { +- this.isForInventoryDrop = true; +- return this; +- } +- + @Override + public MaterialData getData() { + return this.handle != null ? CraftMagicNumbers.getMaterialData(this.handle.getItem()) : super.getData(); diff --git a/patches/server/0903-Dont-resend-blocks-on-interactions.patch b/patches/server/0903-Dont-resend-blocks-on-interactions.patch new file mode 100644 index 0000000000..04f0061970 --- /dev/null +++ b/patches/server/0903-Dont-resend-blocks-on-interactions.patch @@ -0,0 +1,171 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 27 Jun 2023 21:09:11 -0400 +Subject: [PATCH] Dont resend blocks on interactions + +In general, the client now has an acknowledgment system which will prevent block changes made by the client to be reverted correctly. + +It should be noted that this system does not yet support block entities, so those still need to resynced when needed. + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 0da6496c18341c01fc4551ead7e740a6037dcf31..c4bc1819cba3287c4a67ae5d00f8c4d6ab899732 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -202,7 +202,7 @@ public class ServerPlayerGameMode { + PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); + if (event.isCancelled()) { + // Let the client know the block still exists +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync blocks + // Update any tile entity data for this block + capturedBlockEntity = true; // Paper - Send block entities after destroy prediction + return; +@@ -217,7 +217,7 @@ public class ServerPlayerGameMode { + // Spigot start - handle debug stick left click for non-creative + if (this.player.getMainHandItem().is(net.minecraft.world.item.Items.DEBUG_STICK) + && ((net.minecraft.world.item.DebugStickItem) net.minecraft.world.item.Items.DEBUG_STICK).handleInteraction(this.player, this.level.getBlockState(pos), this.level, pos, false, this.player.getMainHandItem())) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync block + return; + } + // Spigot end +@@ -235,15 +235,17 @@ public class ServerPlayerGameMode { + // CraftBukkit start - Swings at air do *NOT* exist. + if (event.useInteractedBlock() == Event.Result.DENY) { + // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. +- BlockState data = this.level.getBlockState(pos); +- if (data.getBlock() instanceof DoorBlock) { +- // For some reason *BOTH* the bottom/top part have to be marked updated. +- boolean bottom = data.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, bottom ? pos.above() : pos.below())); +- } else if (data.getBlock() instanceof TrapDoorBlock) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); +- } ++ // Paper start - Don't resync blocks ++ //BlockState data = this.level.getBlockState(pos); ++ //if (data.getBlock() instanceof DoorBlock) { ++ // // For some reason *BOTH* the bottom/top part have to be marked updated. ++ // boolean bottom = data.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, bottom ? pos.above() : pos.below())); ++ //} else if (data.getBlock() instanceof TrapDoorBlock) { ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ //} ++ // Paper end - Don't resync blocks + } else if (!iblockdata.isAir()) { + EnchantmentHelper.onHitBlock(this.level, this.player.getMainHandItem(), this.player, this.player, EquipmentSlot.MAINHAND, Vec3.atCenterOf(pos), iblockdata, (item) -> { + this.player.onEquippedItemBroken(item, EquipmentSlot.MAINHAND); +@@ -255,7 +257,7 @@ public class ServerPlayerGameMode { + if (event.useItemInHand() == Event.Result.DENY) { + // If we 'insta destroyed' then the client needs to be informed. + if (f > 1.0f) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync blocks + } + return; + } +@@ -263,7 +265,7 @@ public class ServerPlayerGameMode { + + if (blockEvent.isCancelled()) { + // Let the client know the block still exists +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync block + return; + } + +@@ -354,7 +356,7 @@ public class ServerPlayerGameMode { + + // Tell client the block is gone immediately then process events + // Don't tell the client if its a creative sword break because its not broken! +- if (this.level.getBlockEntity(pos) == null && !isSwordNoBreak) { ++ if (false && this.level.getBlockEntity(pos) == null && !isSwordNoBreak) { // Paper - Don't resync block + ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket(pos, Blocks.AIR.defaultBlockState()); + this.player.connection.send(packet); + } +@@ -380,13 +382,15 @@ public class ServerPlayerGameMode { + if (isSwordNoBreak) { + return false; + } ++ // Paper start - Don't resync blocks + // Let the client know the block still exists +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); ++ //this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); + + // Brute force all possible updates +- for (Direction dir : Direction.values()) { +- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos.relative(dir))); +- } ++ //for (Direction dir : Direction.values()) { ++ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos.relative(dir))); ++ //} ++ // Paper end - Don't resync blocks + + // Update any tile entity data for this block + if (!captureSentBlockEntities) { // Paper - Send block entities after destroy prediction +@@ -543,16 +547,18 @@ public class ServerPlayerGameMode { + if (event.useInteractedBlock() == Event.Result.DENY) { + // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. + if (iblockdata.getBlock() instanceof DoorBlock) { +- boolean bottom = iblockdata.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; +- player.connection.send(new ClientboundBlockUpdatePacket(world, bottom ? blockposition.above() : blockposition.below())); ++ // Paper start - Don't resync blocks ++ // boolean bottom = iblockdata.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; ++ // player.connection.send(new ClientboundBlockUpdatePacket(world, bottom ? blockposition.above() : blockposition.below())); ++ // Paper end - Don't resync blocks + } else if (iblockdata.getBlock() instanceof CakeBlock) { + player.getBukkitEntity().sendHealthUpdate(); // SPIGOT-1341 - reset health for cake + } else if (this.interactItemStack.getItem() instanceof DoubleHighBlockItem) { + // send a correcting update to the client, as it already placed the upper half of the bisected item +- player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); ++ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); // Paper - Don't resync blocks + + // send a correcting update to the client for the block above as well, this because of replaceable blocks (such as grass, sea grass etc) +- player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); ++ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); // Paper - Don't resync blocks + // Paper start - extend Player Interact cancellation // TODO: consider merging this into the extracted method + } else if (iblockdata.is(Blocks.JIGSAW) || iblockdata.is(Blocks.STRUCTURE_BLOCK) || iblockdata.getBlock() instanceof net.minecraft.world.level.block.CommandBlock) { + player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId)); +diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java +index 002e2f8e956b2631529e2189be225385dfb501df..3bddfb6f7412ab86e0c090d0cbc6cf254b3f891c 100644 +--- a/src/main/java/net/minecraft/world/item/BucketItem.java ++++ b/src/main/java/net/minecraft/world/item/BucketItem.java +@@ -79,7 +79,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { + PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) world, user, blockposition, blockposition, movingobjectpositionblock.getDirection(), itemstack, dummyFluid.getItem(), hand); + + if (event.isCancelled()) { +- ((ServerPlayer) user).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-5163 (see PlayerInteractManager) ++ // ((ServerPlayer) user).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-5163 (see PlayerInteractManager) // Paper - Don't resend blocks + ((ServerPlayer) user).getBukkitEntity().updateInventory(); // SPIGOT-4541 + return InteractionResult.FAIL; + } +@@ -187,7 +187,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { + if (flag2 && entityhuman != null) { + PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent((ServerLevel) world, entityhuman, blockposition, clicked, enumdirection, itemstack, enumhand); + if (event.isCancelled()) { +- ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity ++ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity // Paper - Don't resend blocks + ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 + return false; + } +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index cb6bcf8b61793882252827309ffa99526244e445..98b5208baeaa12a5ff2788e457c542000d6ea48b 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -506,10 +506,12 @@ public final class ItemStack implements DataComponentHolder { + world.preventPoiUpdated = false; + + // Brute force all possible updates +- BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); +- for (Direction dir : Direction.values()) { +- ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); +- } ++ // Paper start - Don't resync blocks ++ // BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); ++ // for (Direction dir : Direction.values()) { ++ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); ++ // } ++ // Paper end - Don't resync blocks + SignItem.openSign = null; // SPIGOT-6758 - Reset on early return + } else { + // Change the stack to its new contents if it hasn't been tampered with. diff --git a/patches/server/0903-Restore-vanilla-entity-drops-behavior.patch b/patches/server/0903-Restore-vanilla-entity-drops-behavior.patch deleted file mode 100644 index bbad1a93c7..0000000000 --- a/patches/server/0903-Restore-vanilla-entity-drops-behavior.patch +++ /dev/null @@ -1,269 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 22 Mar 2022 09:34:41 -0700 -Subject: [PATCH] Restore vanilla entity drops behavior - -Instead of just tracking the itemstacks, this tracks with it, the -action to take with that itemstack to apply the correct logic -on dropping the item instead of generalizing it for all dropped -items like CB does. - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 419fcb4cd97cf10a2601e02024b999a51a0ff952..df21cd1bd2a3dda7169edbea18bbfdf043db76f8 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1235,20 +1235,20 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - if (this.isRemoved()) { - return; - } -- java.util.List loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); -+ List loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper - Restore vanilla drops behavior - boolean keepInventory = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator(); - - if (!keepInventory) { - for (ItemStack item : this.getInventory().getContents()) { - if (!item.isEmpty() && !EnchantmentHelper.has(item, EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) { -- loot.add(CraftItemStack.asCraftMirror(item).markForInventoryDrop()); -+ loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event) - } - } - } - if (this.shouldDropLoot() && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false - // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule) - this.dropFromLootTable(this.serverLevel(), damageSource, this.lastHurtByPlayerTime > 0); -- this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag); -+ // Paper - Restore vanilla drops behaviour; custom death loot is a noop on server player, remove. - - loot.addAll(this.drops); - this.drops.clear(); // SPIGOT-5188: make sure to clear -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 02b9d280486a23d8eef650566dfaa10ac0b96c9c..cdc5ea3dd9559c076049c86a9fdb4e8bf85ff6c0 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2678,19 +2678,45 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - @Nullable - public ItemEntity spawnAtLocation(ServerLevel world, ItemStack stack, float yOffset) { -+ // Paper start - Restore vanilla drops behavior -+ return this.spawnAtLocation(world, stack, yOffset, null); -+ } -+ public record DefaultDrop(Item item, org.bukkit.inventory.ItemStack stack, @Nullable java.util.function.Consumer dropConsumer) { -+ public DefaultDrop(final ItemStack stack, final java.util.function.Consumer dropConsumer) { -+ this(stack.getItem(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), dropConsumer); -+ } -+ -+ public void runConsumer(final java.util.function.Consumer fallback) { -+ if (this.dropConsumer == null || org.bukkit.craftbukkit.inventory.CraftItemType.bukkitToMinecraft(this.stack.getType()) != this.item) { -+ fallback.accept(this.stack); -+ } else { -+ this.dropConsumer.accept(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(this.stack)); -+ } -+ } -+ } -+ @Nullable -+ public ItemEntity spawnAtLocation(ServerLevel world, ItemStack stack, float yOffset, @Nullable java.util.function.Consumer delayedAddConsumer) { -+ // Paper end - Restore vanilla drops behavior - if (stack.isEmpty()) { - return null; - } else { - // CraftBukkit start - Capture drops for death event - if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) { -- ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later -+ // Paper start - Restore vanilla drops behavior -+ ((net.minecraft.world.entity.LivingEntity) this).drops.add(new net.minecraft.world.entity.Entity.DefaultDrop(stack, itemStack -> { -+ ItemEntity itemEntity = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), itemStack); // stack is copied before consumer -+ itemEntity.setDefaultPickUpDelay(); -+ this.level.addFreshEntity(itemEntity); -+ if (delayedAddConsumer != null) delayedAddConsumer.accept(itemEntity); -+ })); -+ // Paper end - Restore vanilla drops behavior - return null; - } - // CraftBukkit end - ItemEntity entityitem = new ItemEntity(world, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - copy so we can destroy original - stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe - -- entityitem.setDefaultPickUpDelay(); -+ entityitem.setDefaultPickUpDelay(); // Paper - diff on change (in dropConsumer) - // Paper start - Call EntityDropItemEvent - return this.spawnAtLocation(world, entityitem); - } -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 9bc6ed9fd8e5154d39fe12ffed1ecd5ec8e70df8..4b9108e48d052919bca000ddb54f9bf4589c33e6 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -291,7 +291,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - protected float appliedScale; - // CraftBukkit start - public int expToDrop; -- public ArrayList drops = new ArrayList(); -+ public ArrayList drops = new ArrayList<>(); // Paper - Restore vanilla drops behavior - public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes; - public boolean collides = true; - public Set collidableExemptions = new HashSet<>(); -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index e6b18d7f8922cb42acb9e40bef2f71a56aea8646..e1be143959fbaa1d54af2a1a2c27187d70e6a9e9 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -536,10 +536,10 @@ public class WitherBoss extends Monster implements RangedAttackMob { - @Override - protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) { - super.dropCustomDeathLoot(world, source, causedByPlayer); -- ItemEntity entityitem = this.spawnAtLocation(world, (ItemLike) Items.NETHER_STAR); -+ ItemEntity entityitem = this.spawnAtLocation(world, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer - - if (entityitem != null) { -- entityitem.setExtendedLifetime(); -+ entityitem.setExtendedLifetime(); // Paper - diff on change - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -index 2bb2b36f793d25b6e49d1a72bb665cfa9f212730..63f02cdc67d9e88cc6998d0ae9d139c83e85b447 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -619,7 +619,7 @@ public class ArmorStand extends LivingEntity { - ItemStack itemstack = new ItemStack(Items.ARMOR_STAND); - - itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); -- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior - return this.brokenByAnything(world, damageSource); // Paper - } - -@@ -633,7 +633,7 @@ public class ArmorStand extends LivingEntity { - for (i = 0; i < this.handItems.size(); ++i) { - itemstack = (ItemStack) this.handItems.get(i); - if (!itemstack.isEmpty()) { -- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly - this.handItems.set(i, ItemStack.EMPTY); - } - } -@@ -641,7 +641,7 @@ public class ArmorStand extends LivingEntity { - for (i = 0; i < this.armorItems.size(); ++i) { - itemstack = (ItemStack) this.armorItems.get(i); - if (!itemstack.isEmpty()) { -- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly - this.armorItems.set(i, ItemStack.EMPTY); - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index dbef230ae88ee1bfbc20ba53b534434c3ccac985..a0455f590d549343d6d8fd7991ba1b87a87acdb8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -973,19 +973,25 @@ public class CraftEventFactory { - } - - public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource) { -- return CraftEventFactory.callEntityDeathEvent(victim, damageSource, new ArrayList(0)); -+ return CraftEventFactory.callEntityDeathEvent(victim, damageSource, new ArrayList<>(0)); // Paper - Restore vanilla drops behavior - } - -- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops) { -+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops) { // Paper - Restore vanilla drops behavior - // Paper start - return CraftEventFactory.callEntityDeathEvent(victim, damageSource, drops, com.google.common.util.concurrent.Runnables.doNothing()); - } -- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops, Runnable lootCheck) { -+ -+ private static final java.util.function.Function FROM_FUNCTION = stack -> { -+ if (stack == null) return null; -+ return new Entity.DefaultDrop(CraftItemType.bukkitToMinecraft(stack.getType()), stack, null); -+ }; -+ -+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops, Runnable lootCheck) { // Paper - Restore vanilla drops behavior - // Paper end - CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity(); - CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource); - CraftWorld world = (CraftWorld) entity.getWorld(); -- EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(world.getHandle(), damageSource.getEntity())); -+ EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(world.getHandle(), damageSource.getEntity())); // Paper - Restore vanilla drops behavior - populateFields(victim, event); // Paper - make cancellable - Bukkit.getServer().getPluginManager().callEvent(event); - -@@ -998,20 +1004,24 @@ public class CraftEventFactory { - victim.expToDrop = event.getDroppedExp(); - lootCheck.run(); // Paper - advancement triggers before destroying items - -- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { -+ // Paper start - Restore vanilla drops behavior -+ for (Entity.DefaultDrop drop : drops) { -+ if (drop == null) continue; -+ final org.bukkit.inventory.ItemStack stack = drop.stack(); -+ // Paper end - Restore vanilla drops behavior - if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue; - -- world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS -+ drop.runConsumer(s -> world.dropItem(entity.getLocation(), s)); // Paper - Restore vanilla drops behavior - if (stack instanceof CraftItemStack) stack.setAmount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe, but don't nuke bukkit stacks of manually added items - } - - return event; - } - -- public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, DamageSource damageSource, List drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure -+ public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, DamageSource damageSource, List drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure & Restore vanilla drops behavior - CraftPlayer entity = victim.getBukkitEntity(); - CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource); -- PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(victim.serverLevel(), damageSource.getEntity()), 0, deathMessage); -+ PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(victim.serverLevel(), damageSource.getEntity()), 0, deathMessage); // Paper - Restore vanilla drops behavior - event.setKeepInventory(keepInventory); - event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel - populateFields(victim, event); // Paper - make cancellable -@@ -1029,16 +1039,14 @@ public class CraftEventFactory { - victim.expToDrop = event.getDroppedExp(); - victim.newExp = event.getNewExp(); - -- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { -+ // Paper start - Restore vanilla drops behavior -+ for (Entity.DefaultDrop drop : drops) { -+ if (drop == null) continue; -+ final org.bukkit.inventory.ItemStack stack = drop.stack(); -+ // Paper end - Restore vanilla drops behavior - if (stack == null || stack.getType() == Material.AIR) continue; - -- if (stack instanceof CraftItemStack craftItemStack && craftItemStack.isForInventoryDrop()) { -- victim.drop(CraftItemStack.asNMSCopy(stack), true, false, false); // SPIGOT-7800, SPIGOT-7801: Vanilla Behaviour for Player Inventory dropped items -- } else { -- victim.forceDrops = true; -- victim.spawnAtLocation(victim.serverLevel(), CraftItemStack.asNMSCopy(stack)); // SPIGOT-7806: Vanilla Behaviour for items not related to Player Inventory dropped items -- victim.forceDrops = false; -- } -+ drop.runConsumer(s -> victim.drop(CraftItemStack.unwrap(s), true, false, false)); // Paper - Restore vanilla drops behavior - } - - return event; -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 30eba68435387daa3917fa2b3071892c350d9ddc..0b7bc5e83634a26ac6521694377b554c74c6bff0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -142,27 +142,6 @@ public final class CraftItemStack extends ItemStack { - this.setItemMeta(itemMeta); - } - -- /** -- * Gets if the item is marked as an inventory drop in death events. -- * -- * @return true if the item is marked as an inventory drop -- */ -- @ApiStatus.Internal -- public boolean isForInventoryDrop() { -- return this.isForInventoryDrop; -- } -- -- /** -- * Marks this item as an inventory drop in death events. -- * -- * @return the ItemStack marked as an inventory drop -- */ -- @ApiStatus.Internal -- public ItemStack markForInventoryDrop() { -- this.isForInventoryDrop = true; -- return this; -- } -- - @Override - public MaterialData getData() { - return this.handle != null ? CraftMagicNumbers.getMaterialData(this.handle.getItem()) : super.getData(); diff --git a/patches/server/0904-Dont-resend-blocks-on-interactions.patch b/patches/server/0904-Dont-resend-blocks-on-interactions.patch deleted file mode 100644 index 04f0061970..0000000000 --- a/patches/server/0904-Dont-resend-blocks-on-interactions.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Tue, 27 Jun 2023 21:09:11 -0400 -Subject: [PATCH] Dont resend blocks on interactions - -In general, the client now has an acknowledgment system which will prevent block changes made by the client to be reverted correctly. - -It should be noted that this system does not yet support block entities, so those still need to resynced when needed. - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 0da6496c18341c01fc4551ead7e740a6037dcf31..c4bc1819cba3287c4a67ae5d00f8c4d6ab899732 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -202,7 +202,7 @@ public class ServerPlayerGameMode { - PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); - if (event.isCancelled()) { - // Let the client know the block still exists -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync blocks - // Update any tile entity data for this block - capturedBlockEntity = true; // Paper - Send block entities after destroy prediction - return; -@@ -217,7 +217,7 @@ public class ServerPlayerGameMode { - // Spigot start - handle debug stick left click for non-creative - if (this.player.getMainHandItem().is(net.minecraft.world.item.Items.DEBUG_STICK) - && ((net.minecraft.world.item.DebugStickItem) net.minecraft.world.item.Items.DEBUG_STICK).handleInteraction(this.player, this.level.getBlockState(pos), this.level, pos, false, this.player.getMainHandItem())) { -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync block - return; - } - // Spigot end -@@ -235,15 +235,17 @@ public class ServerPlayerGameMode { - // CraftBukkit start - Swings at air do *NOT* exist. - if (event.useInteractedBlock() == Event.Result.DENY) { - // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. -- BlockState data = this.level.getBlockState(pos); -- if (data.getBlock() instanceof DoorBlock) { -- // For some reason *BOTH* the bottom/top part have to be marked updated. -- boolean bottom = data.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, bottom ? pos.above() : pos.below())); -- } else if (data.getBlock() instanceof TrapDoorBlock) { -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -- } -+ // Paper start - Don't resync blocks -+ //BlockState data = this.level.getBlockState(pos); -+ //if (data.getBlock() instanceof DoorBlock) { -+ // // For some reason *BOTH* the bottom/top part have to be marked updated. -+ // boolean bottom = data.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, bottom ? pos.above() : pos.below())); -+ //} else if (data.getBlock() instanceof TrapDoorBlock) { -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ //} -+ // Paper end - Don't resync blocks - } else if (!iblockdata.isAir()) { - EnchantmentHelper.onHitBlock(this.level, this.player.getMainHandItem(), this.player, this.player, EquipmentSlot.MAINHAND, Vec3.atCenterOf(pos), iblockdata, (item) -> { - this.player.onEquippedItemBroken(item, EquipmentSlot.MAINHAND); -@@ -255,7 +257,7 @@ public class ServerPlayerGameMode { - if (event.useItemInHand() == Event.Result.DENY) { - // If we 'insta destroyed' then the client needs to be informed. - if (f > 1.0f) { -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync blocks - } - return; - } -@@ -263,7 +265,7 @@ public class ServerPlayerGameMode { - - if (blockEvent.isCancelled()) { - // Let the client know the block still exists -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); // Paper - Don't resync block - return; - } - -@@ -354,7 +356,7 @@ public class ServerPlayerGameMode { - - // Tell client the block is gone immediately then process events - // Don't tell the client if its a creative sword break because its not broken! -- if (this.level.getBlockEntity(pos) == null && !isSwordNoBreak) { -+ if (false && this.level.getBlockEntity(pos) == null && !isSwordNoBreak) { // Paper - Don't resync block - ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket(pos, Blocks.AIR.defaultBlockState()); - this.player.connection.send(packet); - } -@@ -380,13 +382,15 @@ public class ServerPlayerGameMode { - if (isSwordNoBreak) { - return false; - } -+ // Paper start - Don't resync blocks - // Let the client know the block still exists -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); -+ //this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); - - // Brute force all possible updates -- for (Direction dir : Direction.values()) { -- this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos.relative(dir))); -- } -+ //for (Direction dir : Direction.values()) { -+ // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos.relative(dir))); -+ //} -+ // Paper end - Don't resync blocks - - // Update any tile entity data for this block - if (!captureSentBlockEntities) { // Paper - Send block entities after destroy prediction -@@ -543,16 +547,18 @@ public class ServerPlayerGameMode { - if (event.useInteractedBlock() == Event.Result.DENY) { - // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. - if (iblockdata.getBlock() instanceof DoorBlock) { -- boolean bottom = iblockdata.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; -- player.connection.send(new ClientboundBlockUpdatePacket(world, bottom ? blockposition.above() : blockposition.below())); -+ // Paper start - Don't resync blocks -+ // boolean bottom = iblockdata.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; -+ // player.connection.send(new ClientboundBlockUpdatePacket(world, bottom ? blockposition.above() : blockposition.below())); -+ // Paper end - Don't resync blocks - } else if (iblockdata.getBlock() instanceof CakeBlock) { - player.getBukkitEntity().sendHealthUpdate(); // SPIGOT-1341 - reset health for cake - } else if (this.interactItemStack.getItem() instanceof DoubleHighBlockItem) { - // send a correcting update to the client, as it already placed the upper half of the bisected item -- player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); -+ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); // Paper - Don't resync blocks - - // send a correcting update to the client for the block above as well, this because of replaceable blocks (such as grass, sea grass etc) -- player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); -+ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); // Paper - Don't resync blocks - // Paper start - extend Player Interact cancellation // TODO: consider merging this into the extracted method - } else if (iblockdata.is(Blocks.JIGSAW) || iblockdata.is(Blocks.STRUCTURE_BLOCK) || iblockdata.getBlock() instanceof net.minecraft.world.level.block.CommandBlock) { - player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId)); -diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java -index 002e2f8e956b2631529e2189be225385dfb501df..3bddfb6f7412ab86e0c090d0cbc6cf254b3f891c 100644 ---- a/src/main/java/net/minecraft/world/item/BucketItem.java -+++ b/src/main/java/net/minecraft/world/item/BucketItem.java -@@ -79,7 +79,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { - PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) world, user, blockposition, blockposition, movingobjectpositionblock.getDirection(), itemstack, dummyFluid.getItem(), hand); - - if (event.isCancelled()) { -- ((ServerPlayer) user).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-5163 (see PlayerInteractManager) -+ // ((ServerPlayer) user).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-5163 (see PlayerInteractManager) // Paper - Don't resend blocks - ((ServerPlayer) user).getBukkitEntity().updateInventory(); // SPIGOT-4541 - return InteractionResult.FAIL; - } -@@ -187,7 +187,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { - if (flag2 && entityhuman != null) { - PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent((ServerLevel) world, entityhuman, blockposition, clicked, enumdirection, itemstack, enumhand); - if (event.isCancelled()) { -- ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity -+ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity // Paper - Don't resend blocks - ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 - return false; - } -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index cb6bcf8b61793882252827309ffa99526244e445..98b5208baeaa12a5ff2788e457c542000d6ea48b 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -506,10 +506,12 @@ public final class ItemStack implements DataComponentHolder { - world.preventPoiUpdated = false; - - // Brute force all possible updates -- BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); -- for (Direction dir : Direction.values()) { -- ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); -- } -+ // Paper start - Don't resync blocks -+ // BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); -+ // for (Direction dir : Direction.values()) { -+ // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); -+ // } -+ // Paper end - Don't resync blocks - SignItem.openSign = null; // SPIGOT-6758 - Reset on early return - } else { - // Change the stack to its new contents if it hasn't been tampered with. diff --git a/patches/server/0904-add-more-scoreboard-API.patch b/patches/server/0904-add-more-scoreboard-API.patch new file mode 100644 index 0000000000..3365b53a36 --- /dev/null +++ b/patches/server/0904-add-more-scoreboard-API.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Dec 2023 14:46:01 -0800 +Subject: [PATCH] add more scoreboard API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +index b36e5574c10e6d70a399e2ac0704fd4f43dbb444..2d3abf2a1da487ead74d698cc5ea4eb729c35c8d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +@@ -185,6 +185,19 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective + final CraftObjective other = (CraftObjective) obj; + return !(this.objective != other.objective && (this.objective == null || !this.objective.equals(other.objective))); + } ++ // Paper start - add more score API ++ @Override ++ public boolean willAutoUpdateDisplay() { ++ this.checkState(); ++ return this.objective.displayAutoUpdate(); ++ } ++ ++ @Override ++ public void setAutoUpdateDisplay(final boolean autoUpdateDisplay) { ++ this.checkState(); ++ this.objective.setDisplayAutoUpdate(autoUpdateDisplay); ++ } ++ // Paper end - add more score API + + + } +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +index ceb1a39c02c3cfa7632a0fdca414c7046888fcb1..74d9c407e971804bed420370f7b684d8658eb5aa 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +@@ -74,4 +74,44 @@ final class CraftScore implements Score { + board.resetSinglePlayerScore(entry, this.objective.getHandle()); + } + // Paper end ++ ++ // Paper start - add more score API ++ @Override ++ public boolean isTriggerable() { ++ if (this.objective.getTrackedCriteria() != org.bukkit.scoreboard.Criteria.TRIGGER) { ++ return false; ++ } ++ final Scoreboard board = this.objective.checkState().board; ++ final ReadOnlyScoreInfo scoreInfo = board.getPlayerScoreInfo(this.entry, this.objective.getHandle()); ++ return scoreInfo != null && !scoreInfo.isLocked(); ++ } ++ ++ @Override ++ public void setTriggerable(final boolean triggerable) { ++ com.google.common.base.Preconditions.checkArgument(this.objective.getTrackedCriteria() == org.bukkit.scoreboard.Criteria.TRIGGER, "the criteria isn't 'trigger'"); ++ final Scoreboard board = this.objective.checkState().board; ++ if (triggerable) { ++ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).unlock(); ++ } else { ++ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).lock(); ++ } ++ } ++ ++ @Override ++ public net.kyori.adventure.text.Component customName() { ++ final Scoreboard board = this.objective.checkState().board; ++ final ReadOnlyScoreInfo scoreInfo = board.getPlayerScoreInfo(this.entry, this.objective.getHandle()); ++ if (scoreInfo == null) { ++ return null; // If score doesn't exist, don't create one ++ } ++ final net.minecraft.network.chat.Component display = board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).display(); ++ return display == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(display); ++ } ++ ++ @Override ++ public void customName(final net.kyori.adventure.text.Component customName) { ++ final Scoreboard board = this.objective.checkState().board; ++ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).display(io.papermc.paper.adventure.PaperAdventure.asVanilla(customName)); ++ } ++ // Paper end - add more score API + } diff --git a/patches/server/0905-Improve-Registry.patch b/patches/server/0905-Improve-Registry.patch new file mode 100644 index 0000000000..d5769f63c0 --- /dev/null +++ b/patches/server/0905-Improve-Registry.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 20 Dec 2023 02:03:05 -0800 +Subject: [PATCH] Improve Registry + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index 09929f580164abcd1c04061d04c6aa992767e256..aa66fd8dca886c1f064d8cb4a3d15c2086c1719a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -155,6 +155,7 @@ public class CraftRegistry implements Registry { + + private final Class bukkitClass; // Paper - relax preload class + private final Map cache = new HashMap<>(); ++ private final Map byValue = new java.util.IdentityHashMap<>(); // Paper - improve Registry + private final net.minecraft.core.Registry minecraftRegistry; + private final BiFunction minecraftToBukkit; + private final BiFunction serializationUpdater; // Paper - rename to make it *clear* what it is *only* for +@@ -203,6 +204,7 @@ public class CraftRegistry implements Registry { + } + + this.cache.put(namespacedKey, bukkit); ++ this.byValue.put(bukkit, namespacedKey); // Paper - improve Registry + + return bukkit; + } +@@ -235,4 +237,11 @@ public class CraftRegistry implements Registry { + + return this.minecraftToBukkit.apply(namespacedKey, minecraft); + } ++ ++ // Paper start - improve Registry ++ @Override ++ public NamespacedKey getKey(final B value) { ++ return this.byValue.get(value); ++ } ++ // Paper end - improve Registry + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java +index caf7e4312e95e90dd0822355c8832006e69a2700..38578ef887227ecc8e8bba281eae17a849b4fbe6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java +@@ -54,6 +54,7 @@ public class CraftTrimMaterial implements TrimMaterial, Handleable this + " doesn't have a key"); // Paper + return this.key; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java +index f91577c9239c8d5ed4b72b23dde9c053b4beae0b..36df80a8be8a2485823f699e45c99674dbe71507 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java +@@ -54,6 +54,7 @@ public class CraftTrimPattern implements TrimPattern, Handleable this + " doesn't have a key"); // Paper + return this.key; + } + +diff --git a/src/test/java/org/bukkit/registry/PerRegistryTest.java b/src/test/java/org/bukkit/registry/PerRegistryTest.java +index 18859eea522ff26cbefb5bbc5065b5369ed6c189..319e000519fd719cea0e6daf2ba9cfa67e6958a3 100644 +--- a/src/test/java/org/bukkit/registry/PerRegistryTest.java ++++ b/src/test/java/org/bukkit/registry/PerRegistryTest.java +@@ -49,19 +49,22 @@ public class PerRegistryTest { + + @ParameterizedTest + @MethodSource("data") +- public void testGet(Registry registry) { ++ public void testGet(Registry registry) { // Paper - improve Registry + registry.forEach(element -> { ++ NamespacedKey key = registry.getKey(element); // Paper - improve Registry ++ assertNotNull(key); // Paper - improve Registry + // Values in the registry should be referentially equal to what is returned with #get() + // This ensures that new instances are not created each time #get() is invoked +- assertSame(element, registry.get(element.getKey())); ++ assertSame(element, registry.get(key)); // Paper - improve Registry + }); + } + + @ParameterizedTest + @MethodSource("data") +- public void testMatch(Registry registry) { ++ public void testMatch(Registry registry) { // Paper - improve Registry + registry.forEach(element -> { +- NamespacedKey key = element.getKey(); ++ NamespacedKey key = registry.getKey(element); // Paper - improve Registry ++ assertNotNull(key); // Paper - improve Registry + + this.assertSameMatchWithKeyMessage(registry, element, key.toString()); // namespace:key + this.assertSameMatchWithKeyMessage(registry, element, key.getKey()); // key +@@ -72,7 +75,7 @@ public class PerRegistryTest { + }); + } + +- private void assertSameMatchWithKeyMessage(Registry registry, Keyed element, String key) { ++ private void assertSameMatchWithKeyMessage(Registry registry, T element, String key) { // Paper - improve Registry + assertSame(element, registry.match(key), key); + } + diff --git a/patches/server/0905-add-more-scoreboard-API.patch b/patches/server/0905-add-more-scoreboard-API.patch deleted file mode 100644 index 3365b53a36..0000000000 --- a/patches/server/0905-add-more-scoreboard-API.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 16 Dec 2023 14:46:01 -0800 -Subject: [PATCH] add more scoreboard API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -index b36e5574c10e6d70a399e2ac0704fd4f43dbb444..2d3abf2a1da487ead74d698cc5ea4eb729c35c8d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -@@ -185,6 +185,19 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective - final CraftObjective other = (CraftObjective) obj; - return !(this.objective != other.objective && (this.objective == null || !this.objective.equals(other.objective))); - } -+ // Paper start - add more score API -+ @Override -+ public boolean willAutoUpdateDisplay() { -+ this.checkState(); -+ return this.objective.displayAutoUpdate(); -+ } -+ -+ @Override -+ public void setAutoUpdateDisplay(final boolean autoUpdateDisplay) { -+ this.checkState(); -+ this.objective.setDisplayAutoUpdate(autoUpdateDisplay); -+ } -+ // Paper end - add more score API - - - } -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -index ceb1a39c02c3cfa7632a0fdca414c7046888fcb1..74d9c407e971804bed420370f7b684d8658eb5aa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -@@ -74,4 +74,44 @@ final class CraftScore implements Score { - board.resetSinglePlayerScore(entry, this.objective.getHandle()); - } - // Paper end -+ -+ // Paper start - add more score API -+ @Override -+ public boolean isTriggerable() { -+ if (this.objective.getTrackedCriteria() != org.bukkit.scoreboard.Criteria.TRIGGER) { -+ return false; -+ } -+ final Scoreboard board = this.objective.checkState().board; -+ final ReadOnlyScoreInfo scoreInfo = board.getPlayerScoreInfo(this.entry, this.objective.getHandle()); -+ return scoreInfo != null && !scoreInfo.isLocked(); -+ } -+ -+ @Override -+ public void setTriggerable(final boolean triggerable) { -+ com.google.common.base.Preconditions.checkArgument(this.objective.getTrackedCriteria() == org.bukkit.scoreboard.Criteria.TRIGGER, "the criteria isn't 'trigger'"); -+ final Scoreboard board = this.objective.checkState().board; -+ if (triggerable) { -+ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).unlock(); -+ } else { -+ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).lock(); -+ } -+ } -+ -+ @Override -+ public net.kyori.adventure.text.Component customName() { -+ final Scoreboard board = this.objective.checkState().board; -+ final ReadOnlyScoreInfo scoreInfo = board.getPlayerScoreInfo(this.entry, this.objective.getHandle()); -+ if (scoreInfo == null) { -+ return null; // If score doesn't exist, don't create one -+ } -+ final net.minecraft.network.chat.Component display = board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).display(); -+ return display == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(display); -+ } -+ -+ @Override -+ public void customName(final net.kyori.adventure.text.Component customName) { -+ final Scoreboard board = this.objective.checkState().board; -+ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).display(io.papermc.paper.adventure.PaperAdventure.asVanilla(customName)); -+ } -+ // Paper end - add more score API - } diff --git a/patches/server/0906-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch b/patches/server/0906-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch new file mode 100644 index 0000000000..dc1f06ed56 --- /dev/null +++ b/patches/server/0906-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 9 Dec 2023 19:15:59 -0800 +Subject: [PATCH] Fix NPE on null loc for EntityTeleportEvent + +EntityTeleportEvent#setTo is marked as nullable and so is the +getTo method. This fixes the handling of a null "to" location +by treating it the same as the event being cancelled. This is +already existing behavior for the EntityPortalEvent (which +extends EntityTeleportEvent). + +diff --git a/src/main/java/net/minecraft/server/commands/TeleportCommand.java b/src/main/java/net/minecraft/server/commands/TeleportCommand.java +index c6dcc37ac5fcf50bcb246f533b99983dfc5c19c2..c13b6f14c3061710c2b27034db240cc94ec0fcb5 100644 +--- a/src/main/java/net/minecraft/server/commands/TeleportCommand.java ++++ b/src/main/java/net/minecraft/server/commands/TeleportCommand.java +@@ -181,9 +181,10 @@ public class TeleportCommand { + Location to = new Location(world.getWorld(), d3, d4, d5, f4, f5); + EntityTeleportEvent event = new EntityTeleportEvent(target.getBukkitEntity(), target.getBukkitEntity().getLocation(), to); + world.getCraftServer().getPluginManager().callEvent(event); +- if (event.isCancelled()) { ++ if (event.isCancelled() || event.getTo() == null) { // Paper + return; + } ++ to = event.getTo(); // Paper - actually track new location + + d3 = to.getX(); + d4 = to.getY(); +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index adde7352cdbcb8684f43d6bf5978b6943e9f165b..9d3d6f012cfca60884019ed9710804aa37b11fbf 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -4363,7 +4363,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (!(this instanceof ServerPlayer)) { + EntityTeleportEvent teleport = new EntityTeleportEvent(this.getBukkitEntity(), new Location(this.level().getWorld(), d3, d4, d5), new Location(this.level().getWorld(), d0, d6, d2)); + this.level().getCraftServer().getPluginManager().callEvent(teleport); +- if (!teleport.isCancelled()) { ++ if (!teleport.isCancelled() && teleport.getTo() != null) { // Paper + Location to = teleport.getTo(); + this.teleportTo(to.getX(), to.getY(), to.getZ()); + } else { +diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +index f6a253e063f4a2cf78a036e44431806a0ba270d9..332ae836826270507110f1e0438aaa36d6e9deb5 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -314,7 +314,7 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + } else { + // CraftBukkit start + EntityTeleportEvent event = CraftEventFactory.callEntityTeleportEvent(this, (double) x + 0.5D, (double) y, (double) z + 0.5D); +- if (event.isCancelled()) { ++ if (event.isCancelled() || event.getTo() == null) { // Paper - prevent NP on null event to location + return false; + } + Location to = event.getTo(); +diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java +index dc1870baf172982ebb34eccd4ee79497f48f8050..0fffa9dbcbbb15a2138f9a4e4d8e812c8047a7bb 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java +@@ -416,7 +416,7 @@ public class Shulker extends AbstractGolem implements VariantHolder -Date: Wed, 20 Dec 2023 02:03:05 -0800 -Subject: [PATCH] Improve Registry - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index 09929f580164abcd1c04061d04c6aa992767e256..aa66fd8dca886c1f064d8cb4a3d15c2086c1719a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -155,6 +155,7 @@ public class CraftRegistry implements Registry { - - private final Class bukkitClass; // Paper - relax preload class - private final Map cache = new HashMap<>(); -+ private final Map byValue = new java.util.IdentityHashMap<>(); // Paper - improve Registry - private final net.minecraft.core.Registry minecraftRegistry; - private final BiFunction minecraftToBukkit; - private final BiFunction serializationUpdater; // Paper - rename to make it *clear* what it is *only* for -@@ -203,6 +204,7 @@ public class CraftRegistry implements Registry { - } - - this.cache.put(namespacedKey, bukkit); -+ this.byValue.put(bukkit, namespacedKey); // Paper - improve Registry - - return bukkit; - } -@@ -235,4 +237,11 @@ public class CraftRegistry implements Registry { - - return this.minecraftToBukkit.apply(namespacedKey, minecraft); - } -+ -+ // Paper start - improve Registry -+ @Override -+ public NamespacedKey getKey(final B value) { -+ return this.byValue.get(value); -+ } -+ // Paper end - improve Registry - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java -index caf7e4312e95e90dd0822355c8832006e69a2700..38578ef887227ecc8e8bba281eae17a849b4fbe6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java -@@ -54,6 +54,7 @@ public class CraftTrimMaterial implements TrimMaterial, Handleable this + " doesn't have a key"); // Paper - return this.key; - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java -index f91577c9239c8d5ed4b72b23dde9c053b4beae0b..36df80a8be8a2485823f699e45c99674dbe71507 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java -@@ -54,6 +54,7 @@ public class CraftTrimPattern implements TrimPattern, Handleable this + " doesn't have a key"); // Paper - return this.key; - } - -diff --git a/src/test/java/org/bukkit/registry/PerRegistryTest.java b/src/test/java/org/bukkit/registry/PerRegistryTest.java -index 18859eea522ff26cbefb5bbc5065b5369ed6c189..319e000519fd719cea0e6daf2ba9cfa67e6958a3 100644 ---- a/src/test/java/org/bukkit/registry/PerRegistryTest.java -+++ b/src/test/java/org/bukkit/registry/PerRegistryTest.java -@@ -49,19 +49,22 @@ public class PerRegistryTest { - - @ParameterizedTest - @MethodSource("data") -- public void testGet(Registry registry) { -+ public void testGet(Registry registry) { // Paper - improve Registry - registry.forEach(element -> { -+ NamespacedKey key = registry.getKey(element); // Paper - improve Registry -+ assertNotNull(key); // Paper - improve Registry - // Values in the registry should be referentially equal to what is returned with #get() - // This ensures that new instances are not created each time #get() is invoked -- assertSame(element, registry.get(element.getKey())); -+ assertSame(element, registry.get(key)); // Paper - improve Registry - }); - } - - @ParameterizedTest - @MethodSource("data") -- public void testMatch(Registry registry) { -+ public void testMatch(Registry registry) { // Paper - improve Registry - registry.forEach(element -> { -- NamespacedKey key = element.getKey(); -+ NamespacedKey key = registry.getKey(element); // Paper - improve Registry -+ assertNotNull(key); // Paper - improve Registry - - this.assertSameMatchWithKeyMessage(registry, element, key.toString()); // namespace:key - this.assertSameMatchWithKeyMessage(registry, element, key.getKey()); // key -@@ -72,7 +75,7 @@ public class PerRegistryTest { - }); - } - -- private void assertSameMatchWithKeyMessage(Registry registry, Keyed element, String key) { -+ private void assertSameMatchWithKeyMessage(Registry registry, T element, String key) { // Paper - improve Registry - assertSame(element, registry.match(key), key); - } - diff --git a/patches/server/0907-Add-experience-points-API.patch b/patches/server/0907-Add-experience-points-API.patch new file mode 100644 index 0000000000..1b8c5e9d3f --- /dev/null +++ b/patches/server/0907-Add-experience-points-API.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lukas Planz +Date: Tue, 5 Sep 2023 20:34:20 +0200 +Subject: [PATCH] Add experience points API + + +diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java +index aca888c2f02b09ac6739bdc81b194c4527dd69f5..a19a795deaa7f46c92b97912e2ade006bc90c2d5 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -1823,7 +1823,7 @@ public abstract class Player extends LivingEntity { + } + + public int getXpNeededForNextLevel() { +- return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); ++ return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); // Paper - diff on change; calculateTotalExperiencePoints + } + // Paper start - send while respecting visibility + private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 542c2d85da9695da0f8cc5c34f2e3c0b925dfb7c..0a3d44ac5bfe252854377011ac363d52991c15ed 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1951,6 +1951,49 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + Preconditions.checkArgument(exp >= 0, "Total experience points must not be negative (%s)", exp); + this.getHandle().totalExperience = exp; + } ++ // Paper start ++ @Override ++ public int calculateTotalExperiencePoints() { ++ return calculateTotalExperiencePoints(this.getLevel()) + Math.round(this.getExperiencePointsNeededForNextLevel() * getExp()); ++ } ++ ++ @Override ++ public void setExperienceLevelAndProgress(final int totalExperience) { ++ Preconditions.checkArgument(totalExperience >= 0, "Total experience points must not be negative (%s)", totalExperience); ++ int level = calculateLevelsForExperiencePoints(totalExperience); ++ int remainingPoints = totalExperience - calculateTotalExperiencePoints(level); ++ ++ this.getHandle().experienceLevel = level; ++ this.getHandle().experienceProgress = (float) remainingPoints / this.getExperiencePointsNeededForNextLevel(); ++ this.getHandle().lastSentExp = -1; ++ } ++ ++ @Override ++ public int getExperiencePointsNeededForNextLevel() { ++ return this.getHandle().getXpNeededForNextLevel(); ++ } ++ ++ // See https://minecraft.wiki/w/Experience#Leveling_up for reference ++ private int calculateTotalExperiencePoints(int level) { ++ if (level <= 16) { ++ return (int) (Math.pow(level, 2) + 6 * level); ++ } else if (level <= 31) { ++ return (int) (2.5 * Math.pow(level, 2) - 40.5 * level + 360.0); ++ } else { ++ return (int) (4.5 * Math.pow(level, 2) - 162.5 * level + 2220.0); ++ } ++ } ++ ++ private int calculateLevelsForExperiencePoints(int points) { ++ if (points <= 352) { // Level 0-16 ++ return (int) Math.floor(Math.sqrt(points + 9) - 3); ++ } else if (points <= 1507) { // Level 17-31 ++ return (int) Math.floor(8.1 + Math.sqrt(0.4 * (points - (7839.0 / 40.0)))); ++ } else { // 32+ ++ return (int) Math.floor((325.0 / 18.0) + Math.sqrt((2.0 / 9.0) * (points - (54215.0 / 72.0)))); ++ } ++ } ++ // Paper end + + @Override + public void sendExperienceChange(float progress) { diff --git a/patches/server/0907-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch b/patches/server/0907-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch deleted file mode 100644 index 394a12efc2..0000000000 --- a/patches/server/0907-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 9 Dec 2023 19:15:59 -0800 -Subject: [PATCH] Fix NPE on null loc for EntityTeleportEvent - -EntityTeleportEvent#setTo is marked as nullable and so is the -getTo method. This fixes the handling of a null "to" location -by treating it the same as the event being cancelled. This is -already existing behavior for the EntityPortalEvent (which -extends EntityTeleportEvent). - -diff --git a/src/main/java/net/minecraft/server/commands/TeleportCommand.java b/src/main/java/net/minecraft/server/commands/TeleportCommand.java -index c6dcc37ac5fcf50bcb246f533b99983dfc5c19c2..c13b6f14c3061710c2b27034db240cc94ec0fcb5 100644 ---- a/src/main/java/net/minecraft/server/commands/TeleportCommand.java -+++ b/src/main/java/net/minecraft/server/commands/TeleportCommand.java -@@ -181,9 +181,10 @@ public class TeleportCommand { - Location to = new Location(world.getWorld(), d3, d4, d5, f4, f5); - EntityTeleportEvent event = new EntityTeleportEvent(target.getBukkitEntity(), target.getBukkitEntity().getLocation(), to); - world.getCraftServer().getPluginManager().callEvent(event); -- if (event.isCancelled()) { -+ if (event.isCancelled() || event.getTo() == null) { // Paper - return; - } -+ to = event.getTo(); // Paper - actually track new location - - d3 = to.getX(); - d4 = to.getY(); -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 4b9108e48d052919bca000ddb54f9bf4589c33e6..1c4ec3857c5c3ecf58f842292c280a4a1f00a04c 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4365,7 +4365,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (!(this instanceof ServerPlayer)) { - EntityTeleportEvent teleport = new EntityTeleportEvent(this.getBukkitEntity(), new Location(this.level().getWorld(), d3, d4, d5), new Location(this.level().getWorld(), d0, d6, d2)); - this.level().getCraftServer().getPluginManager().callEvent(teleport); -- if (!teleport.isCancelled()) { -+ if (!teleport.isCancelled() && teleport.getTo() != null) { // Paper - Location to = teleport.getTo(); - this.teleportTo(to.getX(), to.getY(), to.getZ()); - } else { -diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -index f6a253e063f4a2cf78a036e44431806a0ba270d9..332ae836826270507110f1e0438aaa36d6e9deb5 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -314,7 +314,7 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { - } else { - // CraftBukkit start - EntityTeleportEvent event = CraftEventFactory.callEntityTeleportEvent(this, (double) x + 0.5D, (double) y, (double) z + 0.5D); -- if (event.isCancelled()) { -+ if (event.isCancelled() || event.getTo() == null) { // Paper - prevent NP on null event to location - return false; - } - Location to = event.getTo(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index dc1870baf172982ebb34eccd4ee79497f48f8050..0fffa9dbcbbb15a2138f9a4e4d8e812c8047a7bb 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -416,7 +416,7 @@ public class Shulker extends AbstractGolem implements VariantHolder +Date: Tue, 18 May 2021 12:32:02 -0700 +Subject: [PATCH] Add drops to shear events + + +diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +index 9b5a1dc958232e4c2c9631f3504edc6383afd92a..f5206e4176f58cff4cfe70c94f014afebc98c589 100644 +--- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +@@ -103,11 +103,14 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { + if (entityliving instanceof Shearable ishearable) { + if (ishearable.readyForShearing()) { + // CraftBukkit start +- if (CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem).isCancelled()) { ++ // Paper start - Add drops to shear events ++ org.bukkit.event.block.BlockShearEntityEvent event = CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem, ishearable.generateDefaultDrops(worldserver, itemstack)); ++ if (event.isCancelled()) { ++ // Paper end - Add drops to shear events + continue; + } + // CraftBukkit end +- ishearable.shear(worldserver, SoundSource.BLOCKS, itemstack); ++ ishearable.shear(worldserver, SoundSource.BLOCKS, itemstack, CraftItemStack.asNMSCopy(event.getDrops())); // Paper - Add drops to shear events + worldserver.gameEvent((Entity) null, (Holder) GameEvent.SHEAR, blockposition); + return true; + } +diff --git a/src/main/java/net/minecraft/world/entity/Shearable.java b/src/main/java/net/minecraft/world/entity/Shearable.java +index 35076593f3ccd651295ae1fc9bcf8256c19672dd..8fda407c9fbfdde623564a7d9607275c4894b744 100644 +--- a/src/main/java/net/minecraft/world/entity/Shearable.java ++++ b/src/main/java/net/minecraft/world/entity/Shearable.java +@@ -5,8 +5,15 @@ import net.minecraft.sounds.SoundSource; + import net.minecraft.world.item.ItemStack; + + public interface Shearable { ++ default void shear(ServerLevel world, SoundSource soundCategory, ItemStack shears, java.util.List drops) { this.shear(world, soundCategory, shears); } // Paper - Add drops to shear events + void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears); + + boolean readyForShearing(); + net.minecraft.world.level.Level level(); // Shearable API - expose default level needed for shearing. ++ ++ // Paper start - custom shear drops; ensure all implementing entities override this ++ default java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { ++ return java.util.Collections.emptyList(); ++ } ++ // Paper end - custom shear drops + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +index d4d343e2d75a3e3ea787c3c68c64970f5b239f81..feeb7bc34ae02e44d7f13f0bae5d175ef924c53a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +@@ -46,6 +46,7 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables; + // CraftBukkit start + import org.bukkit.Bukkit; + import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; + import org.bukkit.event.entity.EntityDropItemEvent; + import org.bukkit.event.entity.EntityTransformEvent; + // CraftBukkit end +@@ -128,11 +129,18 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder drops = this.generateDefaultDrops(worldserver, itemstack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); ++ if (event != null) { ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); ++ // Paper end - custom shear drops + } + // CraftBukkit end +- this.shear(worldserver, SoundSource.PLAYERS, itemstack); ++ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops + this.gameEvent(GameEvent.SHEAR, player); + itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); + } +@@ -168,22 +176,32 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { ++ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); ++ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (ignored, stack) -> { ++ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1)); ++ }); ++ return drops; ++ } ++ ++ @Override ++ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { ++ // Paper end - custom shear drops + world.playSound((Player) null, (Entity) this, SoundEvents.MOOSHROOM_SHEAR, shearedSoundCategory, 1.0F, 1.0F); + this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), (entitycow) -> { + world.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5D), this.getZ(), 1, 0.0D, 0.0D, 0.0D, 0.0D); +- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (worldserver1, itemstack1) -> { +- for (int i = 0; i < itemstack1.getCount(); ++i) { +- // CraftBukkit start +- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), itemstack1.copyWithCount(1)); +- EntityDropItemEvent event = new EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); +- Bukkit.getPluginManager().callEvent(event); +- if (event.isCancelled()) { +- continue; +- } +- worldserver1.addFreshEntity(entityitem); +- // CraftBukkit end ++ // Paper start - custom shear drops; moved drop generation to separate method ++ drops.forEach(itemstack1 -> { ++ for (final ItemStack drop : drops) { ++ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), drop); ++ this.spawnAtLocation(world, entityitem); + } +- ++ // Paper end - custom shear drops; moved drop generation to separate method + }); + }, EntityTransformEvent.TransformReason.SHEARED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SHEARED); // CraftBukkit + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java +index 1bc638ab505850bffcbd08025de9664dd27e47c6..432ad1c785e133ef18390108fd342be50ec4dddc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java +@@ -173,11 +173,18 @@ public class Sheep extends Animal implements Shearable { + + if (this.readyForShearing()) { + // CraftBukkit start +- if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { +- return InteractionResult.PASS; ++ // Paper start - custom shear drops ++ java.util.List drops = this.generateDefaultDrops(worldserver, itemstack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); ++ if (event != null) { ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); ++ // Paper end - custom shear drops + } + // CraftBukkit end +- this.shear(worldserver, SoundSource.PLAYERS, itemstack); ++ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops + this.gameEvent(GameEvent.SHEAR, player); + itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); + return InteractionResult.SUCCESS_SERVER; +@@ -192,9 +199,26 @@ public class Sheep extends Animal implements Shearable { + + @Override + public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) { ++ // Paper start - custom shear drops ++ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears)); ++ } ++ ++ @Override ++ public java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { ++ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); ++ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_SHEEP, shears, (ignored, stack) -> { ++ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1)); ++ }); ++ return drops; ++ } ++ ++ @Override ++ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { ++ final ServerLevel worldserver1 = world; // Named for lambda consumption ++ // Paper end - custom shear drops + world.playSound((Player) null, (Entity) this, SoundEvents.SHEEP_SHEAR, shearedSoundCategory, 1.0F, 1.0F); +- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_SHEEP, shears, (worldserver1, itemstack1) -> { +- for (int i = 0; i < itemstack1.getCount(); ++i) { ++ drops.forEach(itemstack1 -> { // Paper - custom drops - loop in generated default drops ++ if (true) { // Paper - custom drops - loop in generated default drops + this.forceDrops = true; // CraftBukkit + ItemEntity entityitem = this.spawnAtLocation(worldserver1, itemstack1.copyWithCount(1), 1.0F); + this.forceDrops = false; // CraftBukkit +diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +index 975a9e35303bec29aedfbd554c38e4331cdfb174..fd9f6c17448a4d87f940eb8f544ecb9669068582 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +@@ -161,11 +161,18 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + ServerLevel worldserver = (ServerLevel) world; + + // CraftBukkit start +- if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { +- return InteractionResult.PASS; ++ // Paper start - custom shear drops ++ java.util.List drops = this.generateDefaultDrops(worldserver, itemstack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); ++ if (event != null) { ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); ++ // Paper end - custom shear drops + } + // CraftBukkit end +- this.shear(worldserver, SoundSource.PLAYERS, itemstack); ++ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops + this.gameEvent(GameEvent.SHEAR, player); + itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); + } +@@ -178,9 +185,26 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + + @Override + public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) { ++ // Paper start - custom shear drops ++ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears)); ++ } ++ ++ @Override ++ public java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { ++ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); ++ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (ignored, stack) -> { ++ drops.add(stack); ++ }); ++ return drops; ++ } ++ ++ @Override ++ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { ++ final ServerLevel worldserver1 = world; // Named for lambda consumption ++ // Paper end - custom shear drops + world.playSound((Player) null, (Entity) this, SoundEvents.SNOW_GOLEM_SHEAR, shearedSoundCategory, 1.0F, 1.0F); + this.setPumpkin(false); +- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (worldserver1, itemstack1) -> { ++ drops.forEach(itemstack1 -> { // Paper - custom shear drops + this.forceDrops = true; // CraftBukkit + this.spawnAtLocation(worldserver1, itemstack1, this.getEyeHeight()); + this.forceDrops = false; // CraftBukkit +diff --git a/src/main/java/net/minecraft/world/entity/monster/Bogged.java b/src/main/java/net/minecraft/world/entity/monster/Bogged.java +index 9d416f775fa19ad1978c7c9c9e0d5bc16728879d..18dae37d65552077aa3825c76f433bbd31152db9 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Bogged.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Bogged.java +@@ -27,6 +27,7 @@ import net.minecraft.world.item.Items; + import net.minecraft.world.level.Level; + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.level.storage.loot.BuiltInLootTables; ++import org.bukkit.craftbukkit.event.CraftEventFactory; + + public class Bogged extends AbstractSkeleton implements Shearable { + +@@ -80,12 +81,19 @@ public class Bogged extends AbstractSkeleton implements Shearable { + ServerLevel worldserver = (ServerLevel) world; + + // CraftBukkit start +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { +- this.getEntityData().markDirty(Bogged.DATA_SHEARED); // CraftBukkit - mark dirty to restore sheared state to clients +- return InteractionResult.PASS; ++ // Paper start - custom shear drops ++ java.util.List drops = this.generateDefaultDrops(worldserver, itemstack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); ++ if (event != null) { ++ if (event.isCancelled()) { ++ this.getEntityData().markDirty(Bogged.DATA_SHEARED); // CraftBukkit - mark dirty to restore sheared state to clients ++ return InteractionResult.PASS; ++ } ++ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); ++ // Paper end - custom shear drops + } + // CraftBukkit end +- this.shear(worldserver, SoundSource.PLAYERS, itemstack); ++ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops + this.gameEvent(GameEvent.SHEAR, player); + itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); + } +@@ -139,13 +147,32 @@ public class Bogged extends AbstractSkeleton implements Shearable { + + @Override + public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) { ++ // Paper start - custom shear drops ++ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears)); ++ } ++ ++ @Override ++ public java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { ++ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); ++ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.BOGGED_SHEAR, shears, (ignored, stack) -> { ++ drops.add(stack); ++ }); ++ return drops; ++ } ++ ++ @Override ++ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { ++ // Paper end - custom shear drops + world.playSound((Player) null, (Entity) this, SoundEvents.BOGGED_SHEAR, shearedSoundCategory, 1.0F, 1.0F); +- this.spawnShearedMushrooms(world, shears); ++ this.spawnShearedMushrooms(world, shears, drops); // Paper - custom shear drops + this.setSheared(true); + } + +- private void spawnShearedMushrooms(ServerLevel world, ItemStack shears) { +- this.dropFromShearingLootTable(world, BuiltInLootTables.BOGGED_SHEAR, shears, (worldserver1, itemstack1) -> { ++ // Paper start - custom shear drops ++ private void spawnShearedMushrooms(ServerLevel world, ItemStack shears, java.util.List drops) { ++ final ServerLevel worldserver1 = world; // Named for lambda consumption ++ drops.forEach(itemstack1 -> { ++ // Paper end - custom shear drops + this.spawnAtLocation(worldserver1, itemstack1, this.getBbHeight()); + }); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index a0455f590d549343d6d8fd7991ba1b87a87acdb8..e7749a3ef6289d73379649f2f76f4e4fdfac7a8b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1689,20 +1689,20 @@ public class CraftEventFactory { + player.level().getCraftServer().getPluginManager().callEvent(event); + } + +- public static BlockShearEntityEvent callBlockShearEntityEvent(Entity animal, org.bukkit.block.Block dispenser, CraftItemStack is) { +- BlockShearEntityEvent bse = new BlockShearEntityEvent(dispenser, animal.getBukkitEntity(), is); ++ public static BlockShearEntityEvent callBlockShearEntityEvent(Entity animal, org.bukkit.block.Block dispenser, CraftItemStack is, List drops) { // Paper - custom shear drops ++ BlockShearEntityEvent bse = new BlockShearEntityEvent(dispenser, animal.getBukkitEntity(), is, Lists.transform(drops, CraftItemStack::asCraftMirror)); // Paper - custom shear drops + Bukkit.getPluginManager().callEvent(bse); + return bse; + } + +- public static boolean handlePlayerShearEntityEvent(net.minecraft.world.entity.player.Player player, Entity sheared, ItemStack shears, InteractionHand hand) { ++ public static PlayerShearEntityEvent handlePlayerShearEntityEvent(net.minecraft.world.entity.player.Player player, Entity sheared, ItemStack shears, InteractionHand hand, List drops) { // Paper - custom shear drops + if (!(player instanceof ServerPlayer)) { +- return true; ++ return null; // Paper - custom shear drops + } + +- PlayerShearEntityEvent event = new PlayerShearEntityEvent((Player) player.getBukkitEntity(), sheared.getBukkitEntity(), CraftItemStack.asCraftMirror(shears), (hand == InteractionHand.OFF_HAND ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND)); ++ PlayerShearEntityEvent event = new PlayerShearEntityEvent((Player) player.getBukkitEntity(), sheared.getBukkitEntity(), CraftItemStack.asCraftMirror(shears), (hand == InteractionHand.OFF_HAND ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND), Lists.transform(drops, CraftItemStack::asCraftMirror)); // Paper - custom shear drops + Bukkit.getPluginManager().callEvent(event); +- return !event.isCancelled(); ++ return event; // Paper - custom shear drops + } + + public static Cancellable handleStatisticsIncrease(net.minecraft.world.entity.player.Player entityHuman, net.minecraft.stats.Stat statistic, int current, int newValue) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 0b7bc5e83634a26ac6521694377b554c74c6bff0..ffd7ba14be38a117f5a7d7035a8d71a20fb1c4fc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -74,6 +74,16 @@ public final class CraftItemStack extends ItemStack { + return stack; + } + ++ // Paper start ++ public static java.util.List asNMSCopy(java.util.List originals) { ++ final java.util.List items = new java.util.ArrayList<>(originals.size()); ++ for (final ItemStack original : originals) { ++ items.add(asNMSCopy(original)); ++ } ++ return items; ++ } ++ // Paper end ++ + public static net.minecraft.world.item.ItemStack copyNMSStack(net.minecraft.world.item.ItemStack original, int amount) { + net.minecraft.world.item.ItemStack stack = original.copy(); + stack.setCount(amount); +diff --git a/src/test/java/io/papermc/paper/entity/ShearableDropsTest.java b/src/test/java/io/papermc/paper/entity/ShearableDropsTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5e6dfc93c86ec369b686f15ca066478e1635dbc3 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/entity/ShearableDropsTest.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.entity; ++ ++import io.github.classgraph.ClassGraph; ++import io.github.classgraph.ClassInfo; ++import io.github.classgraph.MethodInfoList; ++import io.github.classgraph.ScanResult; ++import java.util.ArrayList; ++import net.minecraft.world.entity.Shearable; ++import org.bukkit.support.environment.Normal; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++ ++@Normal ++class ShearableDropsTest { ++ ++ static Iterable parameters() { ++ try (ScanResult scanResult = new ClassGraph() ++ .enableClassInfo() ++ .enableMethodInfo() ++ .whitelistPackages("net.minecraft") ++ .scan() ++ ) { ++ return new ArrayList<>(scanResult.getClassesImplementing(Shearable.class.getName())); ++ } ++ } ++ ++ @ParameterizedTest ++ @MethodSource("parameters") ++ void checkShearableDropOverrides(final ClassInfo classInfo) { ++ final MethodInfoList generateDefaultDrops = classInfo.getDeclaredMethodInfo("generateDefaultDrops"); ++ assertEquals(1, generateDefaultDrops.size(), classInfo.getName() + " doesn't implement Shearable#generateDefaultDrops"); ++ } ++} diff --git a/patches/server/0908-Add-experience-points-API.patch b/patches/server/0908-Add-experience-points-API.patch deleted file mode 100644 index 1b8c5e9d3f..0000000000 --- a/patches/server/0908-Add-experience-points-API.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lukas Planz -Date: Tue, 5 Sep 2023 20:34:20 +0200 -Subject: [PATCH] Add experience points API - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index aca888c2f02b09ac6739bdc81b194c4527dd69f5..a19a795deaa7f46c92b97912e2ade006bc90c2d5 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1823,7 +1823,7 @@ public abstract class Player extends LivingEntity { - } - - public int getXpNeededForNextLevel() { -- return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); -+ return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); // Paper - diff on change; calculateTotalExperiencePoints - } - // Paper start - send while respecting visibility - private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 542c2d85da9695da0f8cc5c34f2e3c0b925dfb7c..0a3d44ac5bfe252854377011ac363d52991c15ed 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1951,6 +1951,49 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - Preconditions.checkArgument(exp >= 0, "Total experience points must not be negative (%s)", exp); - this.getHandle().totalExperience = exp; - } -+ // Paper start -+ @Override -+ public int calculateTotalExperiencePoints() { -+ return calculateTotalExperiencePoints(this.getLevel()) + Math.round(this.getExperiencePointsNeededForNextLevel() * getExp()); -+ } -+ -+ @Override -+ public void setExperienceLevelAndProgress(final int totalExperience) { -+ Preconditions.checkArgument(totalExperience >= 0, "Total experience points must not be negative (%s)", totalExperience); -+ int level = calculateLevelsForExperiencePoints(totalExperience); -+ int remainingPoints = totalExperience - calculateTotalExperiencePoints(level); -+ -+ this.getHandle().experienceLevel = level; -+ this.getHandle().experienceProgress = (float) remainingPoints / this.getExperiencePointsNeededForNextLevel(); -+ this.getHandle().lastSentExp = -1; -+ } -+ -+ @Override -+ public int getExperiencePointsNeededForNextLevel() { -+ return this.getHandle().getXpNeededForNextLevel(); -+ } -+ -+ // See https://minecraft.wiki/w/Experience#Leveling_up for reference -+ private int calculateTotalExperiencePoints(int level) { -+ if (level <= 16) { -+ return (int) (Math.pow(level, 2) + 6 * level); -+ } else if (level <= 31) { -+ return (int) (2.5 * Math.pow(level, 2) - 40.5 * level + 360.0); -+ } else { -+ return (int) (4.5 * Math.pow(level, 2) - 162.5 * level + 2220.0); -+ } -+ } -+ -+ private int calculateLevelsForExperiencePoints(int points) { -+ if (points <= 352) { // Level 0-16 -+ return (int) Math.floor(Math.sqrt(points + 9) - 3); -+ } else if (points <= 1507) { // Level 17-31 -+ return (int) Math.floor(8.1 + Math.sqrt(0.4 * (points - (7839.0 / 40.0)))); -+ } else { // 32+ -+ return (int) Math.floor((325.0 / 18.0) + Math.sqrt((2.0 / 9.0) * (points - (54215.0 / 72.0)))); -+ } -+ } -+ // Paper end - - @Override - public void sendExperienceChange(float progress) { diff --git a/patches/server/0909-Add-PlayerShieldDisableEvent.patch b/patches/server/0909-Add-PlayerShieldDisableEvent.patch new file mode 100644 index 0000000000..d2d860a028 --- /dev/null +++ b/patches/server/0909-Add-PlayerShieldDisableEvent.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Mon, 1 May 2023 16:22:43 -0500 +Subject: [PATCH] Add PlayerShieldDisableEvent + +Called whenever a players shield is disabled. This is mainly caused by +attacking players or monsters that carry axes. + +The event, while similar to the PlayerItemCooldownEvent, offers other +behaviour and can hence not be implemented as a childtype of said event. +Specifically, cancelling the event prevents the game events from being +sent to the player. + +Plugins listening to just the PlayerItemCooldownEvent may not want said +sideeffects, meaning the disable event cannot share a handlerlist with +the cooldown event + +diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java +index a19a795deaa7f46c92b97912e2ade006bc90c2d5..61d412c4f1ebd55661cc3f0260468e3ac0efe0bb 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -970,7 +970,7 @@ public abstract class Player extends LivingEntity { + ItemStack itemstack = this.getItemBlockingWith(); + + if (attacker.canDisableShield() && itemstack != null) { +- this.disableShield(itemstack); ++ this.disableShield(itemstack, attacker); // Paper - Add PlayerShieldDisableEvent + } + + } +@@ -1463,8 +1463,21 @@ public abstract class Player extends LivingEntity { + this.attack(target); + } + ++ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - Add PlayerShieldDisableEvent + public void disableShield(ItemStack shield) { +- this.getCooldowns().addCooldown(shield, 100); ++ // Paper start - Add PlayerShieldDisableEvent ++ this.disableShield(shield, null); ++ } ++ public void disableShield(ItemStack shield, @Nullable LivingEntity attacker) { ++ final org.bukkit.entity.Entity finalAttacker = attacker != null ? attacker.getBukkitEntity() : null; ++ if (finalAttacker != null) { ++ final io.papermc.paper.event.player.PlayerShieldDisableEvent shieldDisableEvent = new io.papermc.paper.event.player.PlayerShieldDisableEvent((org.bukkit.entity.Player) getBukkitEntity(), finalAttacker, 100); ++ if (!shieldDisableEvent.callEvent()) return; ++ this.getCooldowns().addCooldown(shield, shieldDisableEvent.getCooldown()); ++ } else { ++ this.getCooldowns().addCooldown(shield, 100); ++ } ++ // Paper end - Add PlayerShieldDisableEvent + this.stopUsingItem(); + this.level().broadcastEntityEvent(this, (byte) 30); + } diff --git a/patches/server/0909-Add-drops-to-shear-events.patch b/patches/server/0909-Add-drops-to-shear-events.patch deleted file mode 100644 index 0ae1794dca..0000000000 --- a/patches/server/0909-Add-drops-to-shear-events.patch +++ /dev/null @@ -1,400 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 18 May 2021 12:32:02 -0700 -Subject: [PATCH] Add drops to shear events - - -diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -index 9b5a1dc958232e4c2c9631f3504edc6383afd92a..f5206e4176f58cff4cfe70c94f014afebc98c589 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -@@ -103,11 +103,14 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { - if (entityliving instanceof Shearable ishearable) { - if (ishearable.readyForShearing()) { - // CraftBukkit start -- if (CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem).isCancelled()) { -+ // Paper start - Add drops to shear events -+ org.bukkit.event.block.BlockShearEntityEvent event = CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem, ishearable.generateDefaultDrops(worldserver, itemstack)); -+ if (event.isCancelled()) { -+ // Paper end - Add drops to shear events - continue; - } - // CraftBukkit end -- ishearable.shear(worldserver, SoundSource.BLOCKS, itemstack); -+ ishearable.shear(worldserver, SoundSource.BLOCKS, itemstack, CraftItemStack.asNMSCopy(event.getDrops())); // Paper - Add drops to shear events - worldserver.gameEvent((Entity) null, (Holder) GameEvent.SHEAR, blockposition); - return true; - } -diff --git a/src/main/java/net/minecraft/world/entity/Shearable.java b/src/main/java/net/minecraft/world/entity/Shearable.java -index 35076593f3ccd651295ae1fc9bcf8256c19672dd..8fda407c9fbfdde623564a7d9607275c4894b744 100644 ---- a/src/main/java/net/minecraft/world/entity/Shearable.java -+++ b/src/main/java/net/minecraft/world/entity/Shearable.java -@@ -5,8 +5,15 @@ import net.minecraft.sounds.SoundSource; - import net.minecraft.world.item.ItemStack; - - public interface Shearable { -+ default void shear(ServerLevel world, SoundSource soundCategory, ItemStack shears, java.util.List drops) { this.shear(world, soundCategory, shears); } // Paper - Add drops to shear events - void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears); - - boolean readyForShearing(); - net.minecraft.world.level.Level level(); // Shearable API - expose default level needed for shearing. -+ -+ // Paper start - custom shear drops; ensure all implementing entities override this -+ default java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { -+ return java.util.Collections.emptyList(); -+ } -+ // Paper end - custom shear drops - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index d4d343e2d75a3e3ea787c3c68c64970f5b239f81..feeb7bc34ae02e44d7f13f0bae5d175ef924c53a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -46,6 +46,7 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables; - // CraftBukkit start - import org.bukkit.Bukkit; - import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; - import org.bukkit.event.entity.EntityDropItemEvent; - import org.bukkit.event.entity.EntityTransformEvent; - // CraftBukkit end -@@ -128,11 +129,18 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder drops = this.generateDefaultDrops(worldserver, itemstack); -+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); -+ if (event != null) { -+ if (event.isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); -+ // Paper end - custom shear drops - } - // CraftBukkit end -- this.shear(worldserver, SoundSource.PLAYERS, itemstack); -+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops - this.gameEvent(GameEvent.SHEAR, player); - itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); - } -@@ -168,22 +176,32 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { -+ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (ignored, stack) -> { -+ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1)); -+ }); -+ return drops; -+ } -+ -+ @Override -+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { -+ // Paper end - custom shear drops - world.playSound((Player) null, (Entity) this, SoundEvents.MOOSHROOM_SHEAR, shearedSoundCategory, 1.0F, 1.0F); - this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), (entitycow) -> { - world.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5D), this.getZ(), 1, 0.0D, 0.0D, 0.0D, 0.0D); -- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (worldserver1, itemstack1) -> { -- for (int i = 0; i < itemstack1.getCount(); ++i) { -- // CraftBukkit start -- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), itemstack1.copyWithCount(1)); -- EntityDropItemEvent event = new EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); -- Bukkit.getPluginManager().callEvent(event); -- if (event.isCancelled()) { -- continue; -- } -- worldserver1.addFreshEntity(entityitem); -- // CraftBukkit end -+ // Paper start - custom shear drops; moved drop generation to separate method -+ drops.forEach(itemstack1 -> { -+ for (final ItemStack drop : drops) { -+ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), drop); -+ this.spawnAtLocation(world, entityitem); - } -- -+ // Paper end - custom shear drops; moved drop generation to separate method - }); - }, EntityTransformEvent.TransformReason.SHEARED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SHEARED); // CraftBukkit - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index 1bc638ab505850bffcbd08025de9664dd27e47c6..432ad1c785e133ef18390108fd342be50ec4dddc 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -173,11 +173,18 @@ public class Sheep extends Animal implements Shearable { - - if (this.readyForShearing()) { - // CraftBukkit start -- if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { -- return InteractionResult.PASS; -+ // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(worldserver, itemstack); -+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); -+ if (event != null) { -+ if (event.isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); -+ // Paper end - custom shear drops - } - // CraftBukkit end -- this.shear(worldserver, SoundSource.PLAYERS, itemstack); -+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops - this.gameEvent(GameEvent.SHEAR, player); - itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); - return InteractionResult.SUCCESS_SERVER; -@@ -192,9 +199,26 @@ public class Sheep extends Animal implements Shearable { - - @Override - public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) { -+ // Paper start - custom shear drops -+ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears)); -+ } -+ -+ @Override -+ public java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { -+ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_SHEEP, shears, (ignored, stack) -> { -+ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1)); -+ }); -+ return drops; -+ } -+ -+ @Override -+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { -+ final ServerLevel worldserver1 = world; // Named for lambda consumption -+ // Paper end - custom shear drops - world.playSound((Player) null, (Entity) this, SoundEvents.SHEEP_SHEAR, shearedSoundCategory, 1.0F, 1.0F); -- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_SHEEP, shears, (worldserver1, itemstack1) -> { -- for (int i = 0; i < itemstack1.getCount(); ++i) { -+ drops.forEach(itemstack1 -> { // Paper - custom drops - loop in generated default drops -+ if (true) { // Paper - custom drops - loop in generated default drops - this.forceDrops = true; // CraftBukkit - ItemEntity entityitem = this.spawnAtLocation(worldserver1, itemstack1.copyWithCount(1), 1.0F); - this.forceDrops = false; // CraftBukkit -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 975a9e35303bec29aedfbd554c38e4331cdfb174..fd9f6c17448a4d87f940eb8f544ecb9669068582 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -161,11 +161,18 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - ServerLevel worldserver = (ServerLevel) world; - - // CraftBukkit start -- if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { -- return InteractionResult.PASS; -+ // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(worldserver, itemstack); -+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); -+ if (event != null) { -+ if (event.isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); -+ // Paper end - custom shear drops - } - // CraftBukkit end -- this.shear(worldserver, SoundSource.PLAYERS, itemstack); -+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops - this.gameEvent(GameEvent.SHEAR, player); - itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); - } -@@ -178,9 +185,26 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - - @Override - public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) { -+ // Paper start - custom shear drops -+ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears)); -+ } -+ -+ @Override -+ public java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { -+ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (ignored, stack) -> { -+ drops.add(stack); -+ }); -+ return drops; -+ } -+ -+ @Override -+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { -+ final ServerLevel worldserver1 = world; // Named for lambda consumption -+ // Paper end - custom shear drops - world.playSound((Player) null, (Entity) this, SoundEvents.SNOW_GOLEM_SHEAR, shearedSoundCategory, 1.0F, 1.0F); - this.setPumpkin(false); -- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (worldserver1, itemstack1) -> { -+ drops.forEach(itemstack1 -> { // Paper - custom shear drops - this.forceDrops = true; // CraftBukkit - this.spawnAtLocation(worldserver1, itemstack1, this.getEyeHeight()); - this.forceDrops = false; // CraftBukkit -diff --git a/src/main/java/net/minecraft/world/entity/monster/Bogged.java b/src/main/java/net/minecraft/world/entity/monster/Bogged.java -index 9d416f775fa19ad1978c7c9c9e0d5bc16728879d..18dae37d65552077aa3825c76f433bbd31152db9 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Bogged.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Bogged.java -@@ -27,6 +27,7 @@ import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; - import net.minecraft.world.level.gameevent.GameEvent; - import net.minecraft.world.level.storage.loot.BuiltInLootTables; -+import org.bukkit.craftbukkit.event.CraftEventFactory; - - public class Bogged extends AbstractSkeleton implements Shearable { - -@@ -80,12 +81,19 @@ public class Bogged extends AbstractSkeleton implements Shearable { - ServerLevel worldserver = (ServerLevel) world; - - // CraftBukkit start -- if (!org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { -- this.getEntityData().markDirty(Bogged.DATA_SHEARED); // CraftBukkit - mark dirty to restore sheared state to clients -- return InteractionResult.PASS; -+ // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(worldserver, itemstack); -+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); -+ if (event != null) { -+ if (event.isCancelled()) { -+ this.getEntityData().markDirty(Bogged.DATA_SHEARED); // CraftBukkit - mark dirty to restore sheared state to clients -+ return InteractionResult.PASS; -+ } -+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); -+ // Paper end - custom shear drops - } - // CraftBukkit end -- this.shear(worldserver, SoundSource.PLAYERS, itemstack); -+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops - this.gameEvent(GameEvent.SHEAR, player); - itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); - } -@@ -139,13 +147,32 @@ public class Bogged extends AbstractSkeleton implements Shearable { - - @Override - public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) { -+ // Paper start - custom shear drops -+ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears)); -+ } -+ -+ @Override -+ public java.util.List generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) { -+ final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.BOGGED_SHEAR, shears, (ignored, stack) -> { -+ drops.add(stack); -+ }); -+ return drops; -+ } -+ -+ @Override -+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { -+ // Paper end - custom shear drops - world.playSound((Player) null, (Entity) this, SoundEvents.BOGGED_SHEAR, shearedSoundCategory, 1.0F, 1.0F); -- this.spawnShearedMushrooms(world, shears); -+ this.spawnShearedMushrooms(world, shears, drops); // Paper - custom shear drops - this.setSheared(true); - } - -- private void spawnShearedMushrooms(ServerLevel world, ItemStack shears) { -- this.dropFromShearingLootTable(world, BuiltInLootTables.BOGGED_SHEAR, shears, (worldserver1, itemstack1) -> { -+ // Paper start - custom shear drops -+ private void spawnShearedMushrooms(ServerLevel world, ItemStack shears, java.util.List drops) { -+ final ServerLevel worldserver1 = world; // Named for lambda consumption -+ drops.forEach(itemstack1 -> { -+ // Paper end - custom shear drops - this.spawnAtLocation(worldserver1, itemstack1, this.getBbHeight()); - }); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index a0455f590d549343d6d8fd7991ba1b87a87acdb8..e7749a3ef6289d73379649f2f76f4e4fdfac7a8b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1689,20 +1689,20 @@ public class CraftEventFactory { - player.level().getCraftServer().getPluginManager().callEvent(event); - } - -- public static BlockShearEntityEvent callBlockShearEntityEvent(Entity animal, org.bukkit.block.Block dispenser, CraftItemStack is) { -- BlockShearEntityEvent bse = new BlockShearEntityEvent(dispenser, animal.getBukkitEntity(), is); -+ public static BlockShearEntityEvent callBlockShearEntityEvent(Entity animal, org.bukkit.block.Block dispenser, CraftItemStack is, List drops) { // Paper - custom shear drops -+ BlockShearEntityEvent bse = new BlockShearEntityEvent(dispenser, animal.getBukkitEntity(), is, Lists.transform(drops, CraftItemStack::asCraftMirror)); // Paper - custom shear drops - Bukkit.getPluginManager().callEvent(bse); - return bse; - } - -- public static boolean handlePlayerShearEntityEvent(net.minecraft.world.entity.player.Player player, Entity sheared, ItemStack shears, InteractionHand hand) { -+ public static PlayerShearEntityEvent handlePlayerShearEntityEvent(net.minecraft.world.entity.player.Player player, Entity sheared, ItemStack shears, InteractionHand hand, List drops) { // Paper - custom shear drops - if (!(player instanceof ServerPlayer)) { -- return true; -+ return null; // Paper - custom shear drops - } - -- PlayerShearEntityEvent event = new PlayerShearEntityEvent((Player) player.getBukkitEntity(), sheared.getBukkitEntity(), CraftItemStack.asCraftMirror(shears), (hand == InteractionHand.OFF_HAND ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND)); -+ PlayerShearEntityEvent event = new PlayerShearEntityEvent((Player) player.getBukkitEntity(), sheared.getBukkitEntity(), CraftItemStack.asCraftMirror(shears), (hand == InteractionHand.OFF_HAND ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND), Lists.transform(drops, CraftItemStack::asCraftMirror)); // Paper - custom shear drops - Bukkit.getPluginManager().callEvent(event); -- return !event.isCancelled(); -+ return event; // Paper - custom shear drops - } - - public static Cancellable handleStatisticsIncrease(net.minecraft.world.entity.player.Player entityHuman, net.minecraft.stats.Stat statistic, int current, int newValue) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 0b7bc5e83634a26ac6521694377b554c74c6bff0..ffd7ba14be38a117f5a7d7035a8d71a20fb1c4fc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -74,6 +74,16 @@ public final class CraftItemStack extends ItemStack { - return stack; - } - -+ // Paper start -+ public static java.util.List asNMSCopy(java.util.List originals) { -+ final java.util.List items = new java.util.ArrayList<>(originals.size()); -+ for (final ItemStack original : originals) { -+ items.add(asNMSCopy(original)); -+ } -+ return items; -+ } -+ // Paper end -+ - public static net.minecraft.world.item.ItemStack copyNMSStack(net.minecraft.world.item.ItemStack original, int amount) { - net.minecraft.world.item.ItemStack stack = original.copy(); - stack.setCount(amount); -diff --git a/src/test/java/io/papermc/paper/entity/ShearableDropsTest.java b/src/test/java/io/papermc/paper/entity/ShearableDropsTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5e6dfc93c86ec369b686f15ca066478e1635dbc3 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/entity/ShearableDropsTest.java -@@ -0,0 +1,35 @@ -+package io.papermc.paper.entity; -+ -+import io.github.classgraph.ClassGraph; -+import io.github.classgraph.ClassInfo; -+import io.github.classgraph.MethodInfoList; -+import io.github.classgraph.ScanResult; -+import java.util.ArrayList; -+import net.minecraft.world.entity.Shearable; -+import org.bukkit.support.environment.Normal; -+import org.junit.jupiter.params.ParameterizedTest; -+import org.junit.jupiter.params.provider.MethodSource; -+ -+import static org.junit.jupiter.api.Assertions.assertEquals; -+ -+@Normal -+class ShearableDropsTest { -+ -+ static Iterable parameters() { -+ try (ScanResult scanResult = new ClassGraph() -+ .enableClassInfo() -+ .enableMethodInfo() -+ .whitelistPackages("net.minecraft") -+ .scan() -+ ) { -+ return new ArrayList<>(scanResult.getClassesImplementing(Shearable.class.getName())); -+ } -+ } -+ -+ @ParameterizedTest -+ @MethodSource("parameters") -+ void checkShearableDropOverrides(final ClassInfo classInfo) { -+ final MethodInfoList generateDefaultDrops = classInfo.getDeclaredMethodInfo("generateDefaultDrops"); -+ assertEquals(1, generateDefaultDrops.size(), classInfo.getName() + " doesn't implement Shearable#generateDefaultDrops"); -+ } -+} diff --git a/patches/server/0910-Add-PlayerShieldDisableEvent.patch b/patches/server/0910-Add-PlayerShieldDisableEvent.patch deleted file mode 100644 index d2d860a028..0000000000 --- a/patches/server/0910-Add-PlayerShieldDisableEvent.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cryptite -Date: Mon, 1 May 2023 16:22:43 -0500 -Subject: [PATCH] Add PlayerShieldDisableEvent - -Called whenever a players shield is disabled. This is mainly caused by -attacking players or monsters that carry axes. - -The event, while similar to the PlayerItemCooldownEvent, offers other -behaviour and can hence not be implemented as a childtype of said event. -Specifically, cancelling the event prevents the game events from being -sent to the player. - -Plugins listening to just the PlayerItemCooldownEvent may not want said -sideeffects, meaning the disable event cannot share a handlerlist with -the cooldown event - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index a19a795deaa7f46c92b97912e2ade006bc90c2d5..61d412c4f1ebd55661cc3f0260468e3ac0efe0bb 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -970,7 +970,7 @@ public abstract class Player extends LivingEntity { - ItemStack itemstack = this.getItemBlockingWith(); - - if (attacker.canDisableShield() && itemstack != null) { -- this.disableShield(itemstack); -+ this.disableShield(itemstack, attacker); // Paper - Add PlayerShieldDisableEvent - } - - } -@@ -1463,8 +1463,21 @@ public abstract class Player extends LivingEntity { - this.attack(target); - } - -+ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - Add PlayerShieldDisableEvent - public void disableShield(ItemStack shield) { -- this.getCooldowns().addCooldown(shield, 100); -+ // Paper start - Add PlayerShieldDisableEvent -+ this.disableShield(shield, null); -+ } -+ public void disableShield(ItemStack shield, @Nullable LivingEntity attacker) { -+ final org.bukkit.entity.Entity finalAttacker = attacker != null ? attacker.getBukkitEntity() : null; -+ if (finalAttacker != null) { -+ final io.papermc.paper.event.player.PlayerShieldDisableEvent shieldDisableEvent = new io.papermc.paper.event.player.PlayerShieldDisableEvent((org.bukkit.entity.Player) getBukkitEntity(), finalAttacker, 100); -+ if (!shieldDisableEvent.callEvent()) return; -+ this.getCooldowns().addCooldown(shield, shieldDisableEvent.getCooldown()); -+ } else { -+ this.getCooldowns().addCooldown(shield, 100); -+ } -+ // Paper end - Add PlayerShieldDisableEvent - this.stopUsingItem(); - this.level().broadcastEntityEvent(this, (byte) 30); - } diff --git a/patches/server/0910-Validate-ResourceLocation-in-NBT-reading.patch b/patches/server/0910-Validate-ResourceLocation-in-NBT-reading.patch new file mode 100644 index 0000000000..a7e42195f1 --- /dev/null +++ b/patches/server/0910-Validate-ResourceLocation-in-NBT-reading.patch @@ -0,0 +1,173 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 4 Jan 2024 13:49:14 +0100 +Subject: [PATCH] Validate ResourceLocation in NBT reading + + +diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java +index 4929bac8e476664086470f078efce6c0a6164413..f88dd37783b3c155c23b547c360b8d3c16e030c0 100644 +--- a/src/main/java/net/minecraft/nbt/NbtUtils.java ++++ b/src/main/java/net/minecraft/nbt/NbtUtils.java +@@ -149,8 +149,10 @@ public final class NbtUtils { + if (!nbt.contains("Name", 8)) { + return Blocks.AIR.defaultBlockState(); + } else { +- ResourceLocation resourceLocation = ResourceLocation.parse(nbt.getString("Name")); +- Optional> optional = blockLookup.get(ResourceKey.create(Registries.BLOCK, resourceLocation)); ++ // Paper start - Validate resource location ++ ResourceLocation resourceLocation = ResourceLocation.tryParse(nbt.getString("Name")); ++ Optional> optional = resourceLocation != null ? blockLookup.get(ResourceKey.create(Registries.BLOCK, resourceLocation)) : Optional.empty(); ++ // Paper end - Validate resource location + if (optional.isEmpty()) { + return Blocks.AIR.defaultBlockState(); + } else { +diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java +index 87afe84791af2d5e9f869cd4c09eed4bb5fee75b..1967c43ee3a12e63365cc40ee6565307e2fd73cf 100644 +--- a/src/main/java/net/minecraft/resources/ResourceLocation.java ++++ b/src/main/java/net/minecraft/resources/ResourceLocation.java +@@ -41,6 +41,13 @@ public final class ResourceLocation implements Comparable { + + assert isValidPath(path); + ++ // Paper start - Validate ResourceLocation ++ // Check for the max network string length (capped at Short.MAX_VALUE) as well as the max bytes of a StringTag (length written as an unsigned short) ++ final String resourceLocation = namespace + ":" + path; ++ if (resourceLocation.length() > Short.MAX_VALUE || io.netty.buffer.ByteBufUtil.utf8MaxBytes(resourceLocation) > 2 * Short.MAX_VALUE + 1) { ++ throw new ResourceLocationException("Resource location too long: " + resourceLocation); ++ } ++ // Paper end - Validate ResourceLocation + this.namespace = namespace; + this.path = path; + } +diff --git a/src/main/java/net/minecraft/world/RandomizableContainer.java b/src/main/java/net/minecraft/world/RandomizableContainer.java +index 084935138b1484f3d96e99f4e5655a6c04931907..9e357abe13f55bd9ce3a1d5348bcf19a15ea5433 100644 +--- a/src/main/java/net/minecraft/world/RandomizableContainer.java ++++ b/src/main/java/net/minecraft/world/RandomizableContainer.java +@@ -50,7 +50,7 @@ public interface RandomizableContainer extends Container { + + default boolean tryLoadLootTable(CompoundTag nbt) { + if (nbt.contains("LootTable", 8)) { +- this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); ++ this.setLootTable(net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl))); // Paper - Validate ResourceLocation + if (this.lootableData() != null && this.getLootTable() != null) this.lootableData().loadNbt(nbt); // Paper - LootTable API + if (nbt.contains("LootTableSeed", 4)) { + this.setLootTableSeed(nbt.getLong("LootTableSeed")); +diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java +index c2693d530be00af16b2aa4ca4afd1d136db68183..629c1316920ad4c111fff489f8c3ea0ed39d0099 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -680,7 +680,7 @@ public class EntityType implements FeatureElement, EntityTypeT + } + + public static Optional> by(CompoundTag nbt) { +- return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.parse(nbt.getString("id"))); ++ return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.tryParse(nbt.getString("id"))); // Paper - Validate ResourceLocation + } + + @Nullable +diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java +index b7721ed97305d1cd6725935f965c2effc1bef5a1..5f880a8809f9c20bc8e8c0b2d48590bab02cf077 100644 +--- a/src/main/java/net/minecraft/world/entity/Leashable.java ++++ b/src/main/java/net/minecraft/world/entity/Leashable.java +@@ -55,7 +55,13 @@ public interface Leashable { + @Nullable + default Leashable.LeashData readLeashData(CompoundTag nbt) { + if (nbt.contains("leash", 10)) { +- return new Leashable.LeashData(Either.left(nbt.getCompound("leash").getUUID("UUID"))); ++ // Paper start ++ final CompoundTag leashTag = nbt.getCompound("leash"); ++ if (!leashTag.hasUUID("UUID")) { ++ return null; ++ } ++ return new Leashable.LeashData(Either.left(leashTag.getUUID("UUID"))); ++ // Paper end + } else { + if (nbt.contains("leash", 11)) { + Either either = (Either) NbtUtils.readBlockPos(nbt, "leash").map(Either::right).orElse(null); // CraftBukkit - decompile error +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 9d3d6f012cfca60884019ed9710804aa37b11fbf..49b3d8d2bc34c0785f143bbc8976308f5bf8c9de 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -909,11 +909,13 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (nbt.contains("SleepingX", 99) && nbt.contains("SleepingY", 99) && nbt.contains("SleepingZ", 99)) { + BlockPos blockposition = new BlockPos(nbt.getInt("SleepingX"), nbt.getInt("SleepingY"), nbt.getInt("SleepingZ")); + ++ if (this.position().distanceToSqr(blockposition.getX(), blockposition.getY(), blockposition.getZ()) < 16 * 16) { // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong + this.setSleepingPos(blockposition); + this.entityData.set(LivingEntity.DATA_POSE, Pose.SLEEPING); + if (!this.firstTick) { + this.setPosToBed(blockposition); + } ++ } // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong + } + + if (nbt.contains("Brain", 10)) { +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index 8a0e65ac8318a467996f48b423db1ac621359fbe..aad63549d7c4f501b683b8dead4938eac27895eb 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -601,7 +601,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + this.leashData = this.readLeashData(nbt); + this.setLeftHanded(nbt.getBoolean("LeftHanded")); + if (nbt.contains("DeathLootTable", 8)) { +- this.lootTable = Optional.of(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("DeathLootTable")))); ++ this.lootTable = Optional.ofNullable(ResourceLocation.tryParse(nbt.getString("DeathLootTable"))).map((rs) -> ResourceKey.create(Registries.LOOT_TABLE, rs)); // Paper - Validate ResourceLocation + this.lootTableSeed = nbt.getLong("DeathLootTableSeed"); + } + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +index 75cc3db39c974abab8510af4a633fc6812efc647..14e31ae88e90d8ea1a98800cc6c1c3527bb2ed6b 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -695,7 +695,7 @@ public abstract class AbstractArrow extends Projectile { + this.setCritArrow(nbt.getBoolean("crit")); + this.setPierceLevel(nbt.getByte("PierceLevel")); + if (nbt.contains("SoundEvent", 8)) { +- this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.parse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); ++ this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.tryParse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); // Paper - Validate resource location + } + + if (nbt.contains("item", 10)) { +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java +index 874a44ab77248665c2db243764e8542bfc0d6514..cc7826a10f22e3307231d887db2fee98063b1f46 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java +@@ -73,7 +73,7 @@ public interface ContainerEntity extends Container, MenuProvider { + default void readChestVehicleSaveData(CompoundTag nbt, HolderLookup.Provider registries) { + this.clearItemStacks(); + if (nbt.contains("LootTable", 8)) { +- this.setContainerLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); ++ this.setContainerLootTable(net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl))); // Paper - Validate ResourceLocation + // Paper start - LootTable API + if (this.getContainerLootTable() != null) { + this.lootableData().loadNbt(nbt); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +index b1067a3add5dc0cfa853b02b5b556d6d67e2932a..15e0861486a2bda3e2f4049b1b5a299c870acd31 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +@@ -180,7 +180,11 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + while (iterator.hasNext()) { + String s = (String) iterator.next(); + +- this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(s)), nbttagcompound1.getInt(s)); ++ // Paper start - Validate ResourceLocation ++ final ResourceLocation resourceLocation = ResourceLocation.tryParse(s); ++ if (resourceLocation != null) { ++ this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, resourceLocation), nbttagcompound1.getInt(s)); ++ } + } + + // Paper start - cook speed multiplier API +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java +index 1bfffbf54b1b440c6e19a908ea2bd70387d06b5c..b08867878e56f88569d547765f29cab018a9e791 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java +@@ -194,7 +194,7 @@ public class BrushableBlockEntity extends BlockEntity { + + private boolean tryLoadLootTable(CompoundTag nbt) { + if (nbt.contains("LootTable", 8)) { +- this.lootTable = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable"))); ++ this.lootTable = net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl)); // Paper - Validate ResourceLocation + this.lootTableSeed = nbt.getLong("LootTableSeed"); + return true; + } else { diff --git a/patches/server/0911-Properly-handle-experience-dropping-on-block-break.patch b/patches/server/0911-Properly-handle-experience-dropping-on-block-break.patch new file mode 100644 index 0000000000..5b45a7fb92 --- /dev/null +++ b/patches/server/0911-Properly-handle-experience-dropping-on-block-break.patch @@ -0,0 +1,94 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sat, 30 Dec 2023 15:00:06 -0500 +Subject: [PATCH] Properly handle experience dropping on block break + +This causes spawnAfterBreak to spawn xp by default, removing the need to manually add xp wherever this method is used. +For classes that use custom xp amounts, they can drop the resources with disabling + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 18c011c1943867dbc4abee338b03b9be499876dd..01fbefdbed48ab85481c811cca532c91860626f7 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -615,7 +615,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + if (drop) { + BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null; + +- Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY); ++ Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping ++ iblockdata.getBlock().popExperience((ServerLevel) this, pos, xp, breakingEntity); // Paper - Properly handle xp dropping; custom amount + } + + boolean flag1 = this.setBlock(pos, fluid.createLegacyBlock(), 3, maxUpdateDepth); +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index 4ff32e3fb1a1979827ef063cda196a43995440fe..dc242451f397ae6a30b830ef1f211f1a066423a4 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -302,23 +302,31 @@ public class Block extends BlockBehaviour implements ItemLike { + for (ItemStack drop : Block.getDrops(state, serverLevel, pos, blockEntity)) { + items.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(drop)); + } ++ Block block = state.getBlock(); // Paper - Properly handle xp dropping + io.papermc.paper.event.block.BlockBreakBlockEvent event = new io.papermc.paper.event.block.BlockBreakBlockEvent(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, pos), org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, source), items); ++ event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping + event.callEvent(); + for (org.bukkit.inventory.ItemStack drop : event.getDrops()) { + popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop)); + } +- state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, true); ++ state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping ++ block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping + } + return true; + } + // Paper end - Add BlockBreakBlockEvent + + public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) { ++ // Paper start - Properly handle xp dropping ++ dropResources(state, world, pos, blockEntity, entity, tool, true); ++ } ++ public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool, boolean dropExperience) { ++ // Paper end - Properly handle xp dropping + if (world instanceof ServerLevel) { + Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { + Block.popResource(world, pos, itemstack1); + }); +- state.spawnAfterBreak((ServerLevel) world, pos, tool, true); ++ state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping + } + + } +@@ -406,7 +414,7 @@ public class Block extends BlockBehaviour implements ItemLike { + player.awardStat(Stats.BLOCK_MINED.get(this)); + player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent + if (includeDrops) { // Paper - fix drops not preventing stats/food exhaustion +- Block.dropResources(state, world, pos, blockEntity, player, tool); ++ Block.dropResources(state, world, pos, blockEntity, player, tool, dropExp); // Paper - Properly handle xp dropping + } // Paper - fix drops not preventing stats/food exhaustion + } + +diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +index 0665ca48fe2f8ab1ce1c0306b11be19b06445f74..1b988b92e80faa1ac224caf9f9e955ac43a4c45a 100644 +--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java ++++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +@@ -1180,6 +1180,7 @@ public abstract class BlockBehaviour implements FeatureElement { + + public void spawnAfterBreak(ServerLevel world, BlockPos pos, ItemStack tool, boolean dropExperience) { + this.getBlock().spawnAfterBreak(this.asState(), world, pos, tool, dropExperience); ++ if (dropExperience) {getBlock().popExperience(world, pos, this.getBlock().getExpDrop(asState(), world, pos, tool, true));} // Paper - Properly handle xp dropping + } + + public List getDrops(LootParams.Builder builder) { +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 6dceb6082538df6f6147254e861d1cec8af7ec50..5cb69d0b822e11a99a96aef4f59986d083b079f4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -509,7 +509,7 @@ public class CraftBlock implements Block { + + // Modelled off EntityHuman#hasBlock + if (block != Blocks.AIR && (item == null || !iblockdata.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(iblockdata))) { +- net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem); ++ net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem, false); // Paper - Properly handle xp dropping + // Paper start - improve Block#breanNaturally + if (triggerEffect) { + if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.BaseFireBlock) { diff --git a/patches/server/0911-Validate-ResourceLocation-in-NBT-reading.patch b/patches/server/0911-Validate-ResourceLocation-in-NBT-reading.patch deleted file mode 100644 index 5a6790a25d..0000000000 --- a/patches/server/0911-Validate-ResourceLocation-in-NBT-reading.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Thu, 4 Jan 2024 13:49:14 +0100 -Subject: [PATCH] Validate ResourceLocation in NBT reading - - -diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java -index 4929bac8e476664086470f078efce6c0a6164413..f88dd37783b3c155c23b547c360b8d3c16e030c0 100644 ---- a/src/main/java/net/minecraft/nbt/NbtUtils.java -+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java -@@ -149,8 +149,10 @@ public final class NbtUtils { - if (!nbt.contains("Name", 8)) { - return Blocks.AIR.defaultBlockState(); - } else { -- ResourceLocation resourceLocation = ResourceLocation.parse(nbt.getString("Name")); -- Optional> optional = blockLookup.get(ResourceKey.create(Registries.BLOCK, resourceLocation)); -+ // Paper start - Validate resource location -+ ResourceLocation resourceLocation = ResourceLocation.tryParse(nbt.getString("Name")); -+ Optional> optional = resourceLocation != null ? blockLookup.get(ResourceKey.create(Registries.BLOCK, resourceLocation)) : Optional.empty(); -+ // Paper end - Validate resource location - if (optional.isEmpty()) { - return Blocks.AIR.defaultBlockState(); - } else { -diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java -index 87afe84791af2d5e9f869cd4c09eed4bb5fee75b..1967c43ee3a12e63365cc40ee6565307e2fd73cf 100644 ---- a/src/main/java/net/minecraft/resources/ResourceLocation.java -+++ b/src/main/java/net/minecraft/resources/ResourceLocation.java -@@ -41,6 +41,13 @@ public final class ResourceLocation implements Comparable { - - assert isValidPath(path); - -+ // Paper start - Validate ResourceLocation -+ // Check for the max network string length (capped at Short.MAX_VALUE) as well as the max bytes of a StringTag (length written as an unsigned short) -+ final String resourceLocation = namespace + ":" + path; -+ if (resourceLocation.length() > Short.MAX_VALUE || io.netty.buffer.ByteBufUtil.utf8MaxBytes(resourceLocation) > 2 * Short.MAX_VALUE + 1) { -+ throw new ResourceLocationException("Resource location too long: " + resourceLocation); -+ } -+ // Paper end - Validate ResourceLocation - this.namespace = namespace; - this.path = path; - } -diff --git a/src/main/java/net/minecraft/world/RandomizableContainer.java b/src/main/java/net/minecraft/world/RandomizableContainer.java -index 084935138b1484f3d96e99f4e5655a6c04931907..9e357abe13f55bd9ce3a1d5348bcf19a15ea5433 100644 ---- a/src/main/java/net/minecraft/world/RandomizableContainer.java -+++ b/src/main/java/net/minecraft/world/RandomizableContainer.java -@@ -50,7 +50,7 @@ public interface RandomizableContainer extends Container { - - default boolean tryLoadLootTable(CompoundTag nbt) { - if (nbt.contains("LootTable", 8)) { -- this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); -+ this.setLootTable(net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl))); // Paper - Validate ResourceLocation - if (this.lootableData() != null && this.getLootTable() != null) this.lootableData().loadNbt(nbt); // Paper - LootTable API - if (nbt.contains("LootTableSeed", 4)) { - this.setLootTableSeed(nbt.getLong("LootTableSeed")); -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index ccee69813597f45d382268bd1792a49722afebe9..e56050bef4a5aaa0fca17192dab4cf5e6a55fbae 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -689,7 +689,7 @@ public class EntityType implements FeatureElement, EntityTypeT - } - - public static Optional> by(CompoundTag nbt) { -- return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.parse(nbt.getString("id"))); -+ return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.tryParse(nbt.getString("id"))); // Paper - Validate ResourceLocation - } - - @Nullable -diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java -index b7721ed97305d1cd6725935f965c2effc1bef5a1..5f880a8809f9c20bc8e8c0b2d48590bab02cf077 100644 ---- a/src/main/java/net/minecraft/world/entity/Leashable.java -+++ b/src/main/java/net/minecraft/world/entity/Leashable.java -@@ -55,7 +55,13 @@ public interface Leashable { - @Nullable - default Leashable.LeashData readLeashData(CompoundTag nbt) { - if (nbt.contains("leash", 10)) { -- return new Leashable.LeashData(Either.left(nbt.getCompound("leash").getUUID("UUID"))); -+ // Paper start -+ final CompoundTag leashTag = nbt.getCompound("leash"); -+ if (!leashTag.hasUUID("UUID")) { -+ return null; -+ } -+ return new Leashable.LeashData(Either.left(leashTag.getUUID("UUID"))); -+ // Paper end - } else { - if (nbt.contains("leash", 11)) { - Either either = (Either) NbtUtils.readBlockPos(nbt, "leash").map(Either::right).orElse(null); // CraftBukkit - decompile error -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 1c4ec3857c5c3ecf58f842292c280a4a1f00a04c..7196340fefd95845f290329faef489f2b2626ecb 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -911,11 +911,13 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (nbt.contains("SleepingX", 99) && nbt.contains("SleepingY", 99) && nbt.contains("SleepingZ", 99)) { - BlockPos blockposition = new BlockPos(nbt.getInt("SleepingX"), nbt.getInt("SleepingY"), nbt.getInt("SleepingZ")); - -+ if (this.position().distanceToSqr(blockposition.getX(), blockposition.getY(), blockposition.getZ()) < 16 * 16) { // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong - this.setSleepingPos(blockposition); - this.entityData.set(LivingEntity.DATA_POSE, Pose.SLEEPING); - if (!this.firstTick) { - this.setPosToBed(blockposition); - } -+ } // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong - } - - if (nbt.contains("Brain", 10)) { -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 8a0e65ac8318a467996f48b423db1ac621359fbe..aad63549d7c4f501b683b8dead4938eac27895eb 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -601,7 +601,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - this.leashData = this.readLeashData(nbt); - this.setLeftHanded(nbt.getBoolean("LeftHanded")); - if (nbt.contains("DeathLootTable", 8)) { -- this.lootTable = Optional.of(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("DeathLootTable")))); -+ this.lootTable = Optional.ofNullable(ResourceLocation.tryParse(nbt.getString("DeathLootTable"))).map((rs) -> ResourceKey.create(Registries.LOOT_TABLE, rs)); // Paper - Validate ResourceLocation - this.lootTableSeed = nbt.getLong("DeathLootTableSeed"); - } - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -index 75cc3db39c974abab8510af4a633fc6812efc647..14e31ae88e90d8ea1a98800cc6c1c3527bb2ed6b 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -695,7 +695,7 @@ public abstract class AbstractArrow extends Projectile { - this.setCritArrow(nbt.getBoolean("crit")); - this.setPierceLevel(nbt.getByte("PierceLevel")); - if (nbt.contains("SoundEvent", 8)) { -- this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.parse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); -+ this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.tryParse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); // Paper - Validate resource location - } - - if (nbt.contains("item", 10)) { -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java -index 874a44ab77248665c2db243764e8542bfc0d6514..cc7826a10f22e3307231d887db2fee98063b1f46 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java -@@ -73,7 +73,7 @@ public interface ContainerEntity extends Container, MenuProvider { - default void readChestVehicleSaveData(CompoundTag nbt, HolderLookup.Provider registries) { - this.clearItemStacks(); - if (nbt.contains("LootTable", 8)) { -- this.setContainerLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); -+ this.setContainerLootTable(net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl))); // Paper - Validate ResourceLocation - // Paper start - LootTable API - if (this.getContainerLootTable() != null) { - this.lootableData().loadNbt(nbt); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index b1067a3add5dc0cfa853b02b5b556d6d67e2932a..15e0861486a2bda3e2f4049b1b5a299c870acd31 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -180,7 +180,11 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - while (iterator.hasNext()) { - String s = (String) iterator.next(); - -- this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(s)), nbttagcompound1.getInt(s)); -+ // Paper start - Validate ResourceLocation -+ final ResourceLocation resourceLocation = ResourceLocation.tryParse(s); -+ if (resourceLocation != null) { -+ this.recipesUsed.put(ResourceKey.create(Registries.RECIPE, resourceLocation), nbttagcompound1.getInt(s)); -+ } - } - - // Paper start - cook speed multiplier API -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java -index 1bfffbf54b1b440c6e19a908ea2bd70387d06b5c..b08867878e56f88569d547765f29cab018a9e791 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java -@@ -194,7 +194,7 @@ public class BrushableBlockEntity extends BlockEntity { - - private boolean tryLoadLootTable(CompoundTag nbt) { - if (nbt.contains("LootTable", 8)) { -- this.lootTable = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable"))); -+ this.lootTable = net.minecraft.Optionull.map(ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(Registries.LOOT_TABLE, rl)); // Paper - Validate ResourceLocation - this.lootTableSeed = nbt.getLong("LootTableSeed"); - return true; - } else { diff --git a/patches/server/0912-Fixup-NamespacedKey-handling.patch b/patches/server/0912-Fixup-NamespacedKey-handling.patch new file mode 100644 index 0000000000..932cc370d8 --- /dev/null +++ b/patches/server/0912-Fixup-NamespacedKey-handling.patch @@ -0,0 +1,170 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sat, 6 Jan 2024 14:31:00 +0100 +Subject: [PATCH] Fixup NamespacedKey handling + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java +index 90b82ad996b2b85628c9a5ddeef9410150b7f70c..5fd22a80e9d05afbea273471cee991732a9485fd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java +@@ -38,7 +38,7 @@ public class CraftLootTable implements org.bukkit.loot.LootTable { + } + + public static org.bukkit.loot.LootTable minecraftToBukkit(ResourceKey minecraft) { +- return (minecraft == null) ? null : Bukkit.getLootTable(CraftLootTable.minecraftToBukkitKey(minecraft)); ++ return (minecraft == null || minecraft.location().getPath().isEmpty()) ? null : Bukkit.getLootTable(CraftLootTable.minecraftToBukkitKey(minecraft)); // Paper - fix some NamespacedKey parsing + } + + public static NamespacedKey minecraftToBukkitKey(ResourceKey minecraft) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index aa66fd8dca886c1f064d8cb4a3d15c2086c1719a..f8450a2abd1e96fac7827d252cc00038b9dee839 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -122,6 +122,16 @@ public class CraftRegistry implements Registry { + + ", this can happen if a plugin creates its own registry entry with out properly registering it."); + } + ++ // Paper start - fixup upstream being dum ++ public static java.util.Optional unwrapAndConvertHolder(final io.papermc.paper.registry.RegistryKey registryKey, final Holder value) { ++ return unwrapAndConvertHolder(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(registryKey), value); ++ } ++ ++ public static java.util.Optional unwrapAndConvertHolder(final Registry registry, final Holder value) { ++ return value.unwrapKey().map(key -> registry.get(CraftNamespacedKey.fromMinecraft(key.location()))); ++ } ++ // Paper end - fixup upstream being dum ++ + // Paper - move to PaperRegistries + + // Paper - NOTE: As long as all uses of the method below relate to *serialization* via ConfigurationSerializable, it's fine +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +index cc97638e038ea64ad180ebfded2528aa07d1809e..10e4318782107644f67818109784fff60d017e0a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +@@ -37,6 +37,7 @@ public class CraftAttribute { + string = FieldRename.convertAttributeName(ApiVersion.CURRENT, string); + string = string.toLowerCase(Locale.ROOT); + NamespacedKey key = NamespacedKey.fromString(string); ++ if (key == null) return null; // Paper - Fixup NamespacedKey handling + + // Now also convert from when keys where saved + return CraftRegistry.get(Registry.ATTRIBUTE, key, ApiVersion.CURRENT); +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java +index afed8bdb9bd6a135e9b5f7bd9bfc61964cb240f7..bb2d1dddca6bfe719b28df136e80a7c5a339a5ce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java +@@ -38,7 +38,11 @@ public class CraftBanner extends CraftBlockEntityState implem + if (banner.getPatterns() != null) { + for (int i = 0; i < banner.getPatterns().layers().size(); i++) { + BannerPatternLayers.Layer p = banner.getPatterns().layers().get(i); +- this.patterns.add(new Pattern(DyeColor.getByWoolData((byte) p.color().getId()), CraftPatternType.minecraftHolderToBukkit(p.pattern()))); ++ // Paper start - fix upstream not handling inlined banner pattern ++ java.util.Optional type = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.BANNER_PATTERN, p.pattern()); ++ if (type.isEmpty()) continue; ++ this.patterns.add(new Pattern(DyeColor.getByWoolData((byte) p.color().getId()), type.get())); ++ // Paper end - fix upstream not handling inlined banner pattern + } + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java +index bcac1359c667ef1ee46384f9c7a5adf4010d2b08..98a4463c9f194f33f4f85d95a0b9fa061cf6faaf 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java +@@ -16,7 +16,7 @@ public class CraftPainting extends CraftHanging implements Painting { + + @Override + public Art getArt() { +- return CraftArt.minecraftHolderToBukkit(this.getHandle().getVariant()); ++ return org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.ART, this.getHandle().getVariant()).orElseThrow(() -> new IllegalStateException("Inlined/custom painting variants are not supported yet in the API!")); // Paper + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +index 0fdd9dd47594a7e7e785c34c09d9b4a79aad2439..0d3b1692af010bfd7ea83e22e9571dc954906f71 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +@@ -38,8 +38,9 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { + super(tag); + + getOrEmpty(tag, CraftMetaArmor.TRIM).ifPresent((trimCompound) -> { +- TrimMaterial trimMaterial = CraftTrimMaterial.minecraftHolderToBukkit(trimCompound.material()); +- TrimPattern trimPattern = CraftTrimPattern.minecraftHolderToBukkit(trimCompound.pattern()); ++ TrimMaterial trimMaterial = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL, trimCompound.material()).orElse(null); // Paper - fix upstream not being correct ++ TrimPattern trimPattern = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_PATTERN, trimCompound.pattern()).orElse(null); // Paper - fix upstream not being correct ++ if (trimMaterial == null || trimPattern == null) return; // Paper - just delete the trim because upstream is not doing this right + + this.trim = new ArmorTrim(trimMaterial, trimPattern); + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +index 1c1a2d66d1ebcbe2ded732e759d0f9d471d43b56..eb44c19f6af624df458981e46c73a64358d6e1ce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +@@ -42,7 +42,7 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { + for (int i = 0; i < Math.min(patterns.size(), 20); i++) { + BannerPatternLayers.Layer p = patterns.get(i); + DyeColor color = DyeColor.getByWoolData((byte) p.color().getId()); +- PatternType pattern = CraftPatternType.minecraftHolderToBukkit(p.pattern()); ++ PatternType pattern = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.BANNER_PATTERN, p.pattern()).orElse(null); // Paper - fix upstream not handling inlined banner pattern + + if (color != null && pattern != null) { + this.patterns.add(new Pattern(color, pattern)); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +index 478059eb3ad76b41e6a20e9b489a2a4fb19e7c7c..76a3e4893cbdba903a712d6db1d30b9c644795be 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +@@ -30,7 +30,7 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst + super(tag); + + getOrEmpty(tag, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT).ifPresent((instrument) -> { +- this.instrument = CraftMusicInstrument.minecraftHolderToBukkit(instrument); ++ this.instrument = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.INSTRUMENT, instrument).orElse(null); // Paper - fix upstream not handling inlined instrument + }); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +index c8eec04685456d89cb41466cddcc3975d0ceeb29..bcd6cc29e4e621805cbd923d747f652ced240c6d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +@@ -17,6 +17,7 @@ import org.bukkit.block.BlockState; + import org.bukkit.block.banner.Pattern; + import org.bukkit.block.banner.PatternType; + import org.bukkit.configuration.serialization.DelegateDeserialization; ++import org.bukkit.craftbukkit.CraftRegistry; + import org.bukkit.craftbukkit.block.CraftBlockStates; + import org.bukkit.craftbukkit.block.banner.CraftPatternType; + import org.bukkit.inventory.meta.BlockStateMeta; +@@ -53,7 +54,7 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + for (int i = 0; i < Math.min(patterns.size(), 20); i++) { + BannerPatternLayers.Layer p = patterns.get(i); + DyeColor color = DyeColor.getByWoolData((byte) p.color().getId()); +- PatternType pattern = CraftPatternType.minecraftHolderToBukkit(p.pattern()); ++ PatternType pattern = CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.BANNER_PATTERN, p.pattern()).orElse(null); // Paper - fix upstream not being correct + + if (color != null && pattern != null) { + this.addPattern(new Pattern(color, pattern)); +diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java +index 82a50b06c08b632f77d73745e1fa9bd22dfd950a..f1d8ed4a2b8959873b02d57f6a40323a841f3d7f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java ++++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java +@@ -69,6 +69,7 @@ public class CraftPotionType implements PotionType.InternalPotionData { + string = FieldRename.convertPotionTypeName(ApiVersion.CURRENT, string); + string = string.toLowerCase(Locale.ROOT); + NamespacedKey key = NamespacedKey.fromString(string); ++ if (key == null) return null; // Paper - Fixup NamespacedKey handling + + // Now also convert from when keys where saved + return CraftRegistry.get(Registry.POTION, key, ApiVersion.CURRENT); +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java +index dc88ba24ed3b0024c39a30c2d90628fc708d63cf..944bed9b6c803df1a312383fed9de7d61e7d2c70 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java +@@ -13,7 +13,7 @@ public final class CraftNamespacedKey { + return null; + } + ResourceLocation minecraft = ResourceLocation.tryParse(string); +- return (minecraft == null) ? null : CraftNamespacedKey.fromMinecraft(minecraft); ++ return (minecraft == null || minecraft.getPath().isEmpty()) ? null : CraftNamespacedKey.fromMinecraft(minecraft); // Paper - Bukkit's parser does not match Vanilla for empty paths + } + + public static NamespacedKey fromString(String string) { diff --git a/patches/server/0912-Properly-handle-experience-dropping-on-block-break.patch b/patches/server/0912-Properly-handle-experience-dropping-on-block-break.patch deleted file mode 100644 index e5caf980cd..0000000000 --- a/patches/server/0912-Properly-handle-experience-dropping-on-block-break.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sat, 30 Dec 2023 15:00:06 -0500 -Subject: [PATCH] Properly handle experience dropping on block break - -This causes spawnAfterBreak to spawn xp by default, removing the need to manually add xp wherever this method is used. -For classes that use custom xp amounts, they can drop the resources with disabling - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index d048d0e4b16459b5bad44ebfa3c6a8f336f6762b..83537aa240ebff8dd19b450956730dc3d4f355a0 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -617,7 +617,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - if (drop) { - BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null; - -- Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY); -+ Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping -+ iblockdata.getBlock().popExperience((ServerLevel) this, pos, xp, breakingEntity); // Paper - Properly handle xp dropping; custom amount - } - - boolean flag1 = this.setBlock(pos, fluid.createLegacyBlock(), 3, maxUpdateDepth); -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 6fb3f551f432d7e668c606fb7bd3514408e0478a..9917df070d9815b6915e4a0b022dfe4e5b7861e7 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -311,23 +311,31 @@ public class Block extends BlockBehaviour implements ItemLike { - for (ItemStack drop : Block.getDrops(state, serverLevel, pos, blockEntity)) { - items.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(drop)); - } -+ Block block = state.getBlock(); // Paper - Properly handle xp dropping - io.papermc.paper.event.block.BlockBreakBlockEvent event = new io.papermc.paper.event.block.BlockBreakBlockEvent(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, pos), org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, source), items); -+ event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping - event.callEvent(); - for (org.bukkit.inventory.ItemStack drop : event.getDrops()) { - popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop)); - } -- state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, true); -+ state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping -+ block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping - } - return true; - } - // Paper end - Add BlockBreakBlockEvent - - public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) { -+ // Paper start - Properly handle xp dropping -+ dropResources(state, world, pos, blockEntity, entity, tool, true); -+ } -+ public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool, boolean dropExperience) { -+ // Paper end - Properly handle xp dropping - if (world instanceof ServerLevel) { - Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { - Block.popResource(world, pos, itemstack1); - }); -- state.spawnAfterBreak((ServerLevel) world, pos, tool, true); -+ state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping - } - - } -@@ -415,7 +423,7 @@ public class Block extends BlockBehaviour implements ItemLike { - player.awardStat(Stats.BLOCK_MINED.get(this)); - player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent - if (includeDrops) { // Paper - fix drops not preventing stats/food exhaustion -- Block.dropResources(state, world, pos, blockEntity, player, tool); -+ Block.dropResources(state, world, pos, blockEntity, player, tool, dropExp); // Paper - Properly handle xp dropping - } // Paper - fix drops not preventing stats/food exhaustion - } - -diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 0665ca48fe2f8ab1ce1c0306b11be19b06445f74..1b988b92e80faa1ac224caf9f9e955ac43a4c45a 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -1180,6 +1180,7 @@ public abstract class BlockBehaviour implements FeatureElement { - - public void spawnAfterBreak(ServerLevel world, BlockPos pos, ItemStack tool, boolean dropExperience) { - this.getBlock().spawnAfterBreak(this.asState(), world, pos, tool, dropExperience); -+ if (dropExperience) {getBlock().popExperience(world, pos, this.getBlock().getExpDrop(asState(), world, pos, tool, true));} // Paper - Properly handle xp dropping - } - - public List getDrops(LootParams.Builder builder) { -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 6dceb6082538df6f6147254e861d1cec8af7ec50..5cb69d0b822e11a99a96aef4f59986d083b079f4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -509,7 +509,7 @@ public class CraftBlock implements Block { - - // Modelled off EntityHuman#hasBlock - if (block != Blocks.AIR && (item == null || !iblockdata.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(iblockdata))) { -- net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem); -+ net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem, false); // Paper - Properly handle xp dropping - // Paper start - improve Block#breanNaturally - if (triggerEffect) { - if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.BaseFireBlock) { diff --git a/patches/server/0913-Expose-LootTable-of-DecoratedPot.patch b/patches/server/0913-Expose-LootTable-of-DecoratedPot.patch new file mode 100644 index 0000000000..afa86977a9 --- /dev/null +++ b/patches/server/0913-Expose-LootTable-of-DecoratedPot.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: FireInstall +Date: Sat, 20 Jan 2024 16:20:06 +0100 +Subject: [PATCH] Expose LootTable of DecoratedPot + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java +index 6e0258d4d6a07e0f471640a9edda0adf7ef6cd9e..47cc3ec5ccd3bb51a08b3f179cb29030948b8c11 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java +@@ -43,6 +43,33 @@ public class CraftDecoratedPot extends CraftBlockEntityState -Date: Sat, 6 Jan 2024 14:31:00 +0100 -Subject: [PATCH] Fixup NamespacedKey handling - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java -index 90b82ad996b2b85628c9a5ddeef9410150b7f70c..5fd22a80e9d05afbea273471cee991732a9485fd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java -@@ -38,7 +38,7 @@ public class CraftLootTable implements org.bukkit.loot.LootTable { - } - - public static org.bukkit.loot.LootTable minecraftToBukkit(ResourceKey minecraft) { -- return (minecraft == null) ? null : Bukkit.getLootTable(CraftLootTable.minecraftToBukkitKey(minecraft)); -+ return (minecraft == null || minecraft.location().getPath().isEmpty()) ? null : Bukkit.getLootTable(CraftLootTable.minecraftToBukkitKey(minecraft)); // Paper - fix some NamespacedKey parsing - } - - public static NamespacedKey minecraftToBukkitKey(ResourceKey minecraft) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index aa66fd8dca886c1f064d8cb4a3d15c2086c1719a..f8450a2abd1e96fac7827d252cc00038b9dee839 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -122,6 +122,16 @@ public class CraftRegistry implements Registry { - + ", this can happen if a plugin creates its own registry entry with out properly registering it."); - } - -+ // Paper start - fixup upstream being dum -+ public static java.util.Optional unwrapAndConvertHolder(final io.papermc.paper.registry.RegistryKey registryKey, final Holder value) { -+ return unwrapAndConvertHolder(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(registryKey), value); -+ } -+ -+ public static java.util.Optional unwrapAndConvertHolder(final Registry registry, final Holder value) { -+ return value.unwrapKey().map(key -> registry.get(CraftNamespacedKey.fromMinecraft(key.location()))); -+ } -+ // Paper end - fixup upstream being dum -+ - // Paper - move to PaperRegistries - - // Paper - NOTE: As long as all uses of the method below relate to *serialization* via ConfigurationSerializable, it's fine -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -index cc97638e038ea64ad180ebfded2528aa07d1809e..10e4318782107644f67818109784fff60d017e0a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -@@ -37,6 +37,7 @@ public class CraftAttribute { - string = FieldRename.convertAttributeName(ApiVersion.CURRENT, string); - string = string.toLowerCase(Locale.ROOT); - NamespacedKey key = NamespacedKey.fromString(string); -+ if (key == null) return null; // Paper - Fixup NamespacedKey handling - - // Now also convert from when keys where saved - return CraftRegistry.get(Registry.ATTRIBUTE, key, ApiVersion.CURRENT); -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java -index afed8bdb9bd6a135e9b5f7bd9bfc61964cb240f7..bb2d1dddca6bfe719b28df136e80a7c5a339a5ce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java -@@ -38,7 +38,11 @@ public class CraftBanner extends CraftBlockEntityState implem - if (banner.getPatterns() != null) { - for (int i = 0; i < banner.getPatterns().layers().size(); i++) { - BannerPatternLayers.Layer p = banner.getPatterns().layers().get(i); -- this.patterns.add(new Pattern(DyeColor.getByWoolData((byte) p.color().getId()), CraftPatternType.minecraftHolderToBukkit(p.pattern()))); -+ // Paper start - fix upstream not handling inlined banner pattern -+ java.util.Optional type = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.BANNER_PATTERN, p.pattern()); -+ if (type.isEmpty()) continue; -+ this.patterns.add(new Pattern(DyeColor.getByWoolData((byte) p.color().getId()), type.get())); -+ // Paper end - fix upstream not handling inlined banner pattern - } - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -index bcac1359c667ef1ee46384f9c7a5adf4010d2b08..98a4463c9f194f33f4f85d95a0b9fa061cf6faaf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -@@ -16,7 +16,7 @@ public class CraftPainting extends CraftHanging implements Painting { - - @Override - public Art getArt() { -- return CraftArt.minecraftHolderToBukkit(this.getHandle().getVariant()); -+ return org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.ART, this.getHandle().getVariant()).orElseThrow(() -> new IllegalStateException("Inlined/custom painting variants are not supported yet in the API!")); // Paper - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -index 0fdd9dd47594a7e7e785c34c09d9b4a79aad2439..0d3b1692af010bfd7ea83e22e9571dc954906f71 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -@@ -38,8 +38,9 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { - super(tag); - - getOrEmpty(tag, CraftMetaArmor.TRIM).ifPresent((trimCompound) -> { -- TrimMaterial trimMaterial = CraftTrimMaterial.minecraftHolderToBukkit(trimCompound.material()); -- TrimPattern trimPattern = CraftTrimPattern.minecraftHolderToBukkit(trimCompound.pattern()); -+ TrimMaterial trimMaterial = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL, trimCompound.material()).orElse(null); // Paper - fix upstream not being correct -+ TrimPattern trimPattern = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_PATTERN, trimCompound.pattern()).orElse(null); // Paper - fix upstream not being correct -+ if (trimMaterial == null || trimPattern == null) return; // Paper - just delete the trim because upstream is not doing this right - - this.trim = new ArmorTrim(trimMaterial, trimPattern); - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -index 1c1a2d66d1ebcbe2ded732e759d0f9d471d43b56..eb44c19f6af624df458981e46c73a64358d6e1ce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -@@ -42,7 +42,7 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { - for (int i = 0; i < Math.min(patterns.size(), 20); i++) { - BannerPatternLayers.Layer p = patterns.get(i); - DyeColor color = DyeColor.getByWoolData((byte) p.color().getId()); -- PatternType pattern = CraftPatternType.minecraftHolderToBukkit(p.pattern()); -+ PatternType pattern = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.BANNER_PATTERN, p.pattern()).orElse(null); // Paper - fix upstream not handling inlined banner pattern - - if (color != null && pattern != null) { - this.patterns.add(new Pattern(color, pattern)); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -index 478059eb3ad76b41e6a20e9b489a2a4fb19e7c7c..76a3e4893cbdba903a712d6db1d30b9c644795be 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -@@ -30,7 +30,7 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst - super(tag); - - getOrEmpty(tag, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT).ifPresent((instrument) -> { -- this.instrument = CraftMusicInstrument.minecraftHolderToBukkit(instrument); -+ this.instrument = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.INSTRUMENT, instrument).orElse(null); // Paper - fix upstream not handling inlined instrument - }); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -index c8eec04685456d89cb41466cddcc3975d0ceeb29..bcd6cc29e4e621805cbd923d747f652ced240c6d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -@@ -17,6 +17,7 @@ import org.bukkit.block.BlockState; - import org.bukkit.block.banner.Pattern; - import org.bukkit.block.banner.PatternType; - import org.bukkit.configuration.serialization.DelegateDeserialization; -+import org.bukkit.craftbukkit.CraftRegistry; - import org.bukkit.craftbukkit.block.CraftBlockStates; - import org.bukkit.craftbukkit.block.banner.CraftPatternType; - import org.bukkit.inventory.meta.BlockStateMeta; -@@ -53,7 +54,7 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - for (int i = 0; i < Math.min(patterns.size(), 20); i++) { - BannerPatternLayers.Layer p = patterns.get(i); - DyeColor color = DyeColor.getByWoolData((byte) p.color().getId()); -- PatternType pattern = CraftPatternType.minecraftHolderToBukkit(p.pattern()); -+ PatternType pattern = CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.BANNER_PATTERN, p.pattern()).orElse(null); // Paper - fix upstream not being correct - - if (color != null && pattern != null) { - this.addPattern(new Pattern(color, pattern)); -diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java -index 82a50b06c08b632f77d73745e1fa9bd22dfd950a..f1d8ed4a2b8959873b02d57f6a40323a841f3d7f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java -+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java -@@ -69,6 +69,7 @@ public class CraftPotionType implements PotionType.InternalPotionData { - string = FieldRename.convertPotionTypeName(ApiVersion.CURRENT, string); - string = string.toLowerCase(Locale.ROOT); - NamespacedKey key = NamespacedKey.fromString(string); -+ if (key == null) return null; // Paper - Fixup NamespacedKey handling - - // Now also convert from when keys where saved - return CraftRegistry.get(Registry.POTION, key, ApiVersion.CURRENT); -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java -index dc88ba24ed3b0024c39a30c2d90628fc708d63cf..944bed9b6c803df1a312383fed9de7d61e7d2c70 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java -@@ -13,7 +13,7 @@ public final class CraftNamespacedKey { - return null; - } - ResourceLocation minecraft = ResourceLocation.tryParse(string); -- return (minecraft == null) ? null : CraftNamespacedKey.fromMinecraft(minecraft); -+ return (minecraft == null || minecraft.getPath().isEmpty()) ? null : CraftNamespacedKey.fromMinecraft(minecraft); // Paper - Bukkit's parser does not match Vanilla for empty paths - } - - public static NamespacedKey fromString(String string) { diff --git a/patches/server/0914-Expose-LootTable-of-DecoratedPot.patch b/patches/server/0914-Expose-LootTable-of-DecoratedPot.patch deleted file mode 100644 index afa86977a9..0000000000 --- a/patches/server/0914-Expose-LootTable-of-DecoratedPot.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: FireInstall -Date: Sat, 20 Jan 2024 16:20:06 +0100 -Subject: [PATCH] Expose LootTable of DecoratedPot - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java -index 6e0258d4d6a07e0f471640a9edda0adf7ef6cd9e..47cc3ec5ccd3bb51a08b3f179cb29030948b8c11 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDecoratedPot.java -@@ -43,6 +43,33 @@ public class CraftDecoratedPot extends CraftBlockEntityState +Date: Mon, 27 Apr 2020 00:04:16 -0700 +Subject: [PATCH] Reduce allocation of Vec3D by entity tracker + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java +index a043ac10834562d357ef0b5aded2e916e2a0d056..74276c368016fcc4dbf9579b2ecbadc9614baf15 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java ++++ b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java +@@ -5,7 +5,7 @@ import org.jetbrains.annotations.VisibleForTesting; + + public class VecDeltaCodec { + private static final double TRUNCATION_STEPS = 4096.0; +- private Vec3 base = Vec3.ZERO; ++ public Vec3 base = Vec3.ZERO; // Paper + + @VisibleForTesting + static long encode(double value) { +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index bf6d5f9e23387da845d6fe246c9013ec4d13cfb1..9b64dfe8f1727519673cc87be2398d43601e68ef 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1572,10 +1572,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + public void updatePlayer(ServerPlayer player) { + org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot + if (player != this.entity) { +- Vec3 vec3d = player.position().subtract(this.entity.position()); ++ // Paper start - remove allocation of Vec3D here ++ // Vec3 vec3d = player.position().subtract(this.entity.position()); ++ double vec3d_dx = player.getX() - this.entity.getX(); ++ double vec3d_dz = player.getZ() - this.entity.getZ(); ++ // Paper end - remove allocation of Vec3D here + int i = ChunkMap.this.getPlayerViewDistance(player); + double d0 = (double) Math.min(this.getEffectiveRange(), i * 16); +- double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; ++ double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper + double d2 = d0 * d0; + // Paper start - Configurable entity tracking range by Y + boolean flag = d1 <= d2; +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 7118e1f806af98159ec292f9340d7e4004e2b486..f3456aeeab7eee5b6d0383a4bf1338dd8cc95bb3 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -178,7 +178,13 @@ public class ServerEntity { + + ++this.teleportDelay; + Vec3 vec3d = this.entity.trackingPosition(); +- boolean flag1 = this.positionCodec.delta(vec3d).lengthSqr() >= 7.62939453125E-6D; ++ // Paper start - reduce allocation of Vec3D here ++ Vec3 base = this.positionCodec.base; ++ double vec3d_dx = vec3d.x - base.x; ++ double vec3d_dy = vec3d.y - base.y; ++ double vec3d_dz = vec3d.z - base.z; ++ boolean flag1 = (vec3d_dx * vec3d_dx + vec3d_dy * vec3d_dy + vec3d_dz * vec3d_dz) >= 7.62939453125E-6D; ++ // Paper end - reduce allocation of Vec3D here + Packet packet1 = null; + boolean flag2 = flag1 || this.tickCount % 60 == 0; + boolean flag3 = false; diff --git a/patches/server/0915-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch b/patches/server/0915-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch new file mode 100644 index 0000000000..4ed1121ea1 --- /dev/null +++ b/patches/server/0915-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch @@ -0,0 +1,240 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 2 Jul 2020 16:12:10 -0700 +Subject: [PATCH] Add PlayerTradeEvent and PlayerPurchaseEvent + +Co-authored-by: Alexander + +diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java +index 39cb40b077e9c07471437d5bec16ba9a7e6bce52..5f656fc726a1dc5f42657095a2f2b7cf85b92d7c 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java +@@ -141,11 +141,24 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa + @Override + public void overrideXp(int experience) {} + ++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent ++ @Override ++ public void processTrade(MerchantOffer recipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent ++ if (event == null || event.willIncreaseTradeUses()) { ++ recipe.increaseUses(); ++ } ++ if (event == null || event.isRewardingExp()) { ++ this.rewardTradeXp(recipe); ++ } ++ this.notifyTrade(recipe); ++ } ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent ++ + @Override + public void notifyTrade(MerchantOffer offer) { +- offer.increaseUses(); ++ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + this.ambientSoundTime = -this.getAmbientSoundInterval(); +- this.rewardTradeXp(offer); ++ // this.rewardTradeXp(offer); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + if (this.tradingPlayer instanceof ServerPlayer) { + CriteriaTriggers.TRADE.trigger((ServerPlayer) this.tradingPlayer, this, offer.getResult()); + } +diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +index 85caec29a705f216eff8a5ae11f250697891a05c..78d0ff45c016e900d87010e8b26b0bb10e63f445 100644 +--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -831,6 +831,14 @@ public abstract class AbstractContainerMenu { + public abstract boolean stillValid(Player player); + + protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast) { ++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent ++ return this.moveItemStackTo(stack, startIndex, endIndex, fromLast, false); ++ } ++ protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast, boolean isCheck) { ++ if (isCheck) { ++ stack = stack.copy(); ++ } ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + boolean flag1 = false; + int k = startIndex; + +@@ -854,6 +862,11 @@ public abstract class AbstractContainerMenu { + + slot = (Slot) this.slots.get(k); + itemstack1 = slot.getItem(); ++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; clone if only a check ++ if (isCheck) { ++ itemstack1 = itemstack1.copy(); ++ } ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + if (!itemstack1.isEmpty() && ItemStack.isSameItemSameComponents(stack, itemstack1)) { + l = itemstack1.getCount() + stack.getCount(); + int i1 = slot.getMaxStackSize(itemstack1); +@@ -861,12 +874,16 @@ public abstract class AbstractContainerMenu { + if (l <= i1) { + stack.setCount(0); + itemstack1.setCount(l); ++ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + slot.setChanged(); ++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + flag1 = true; + } else if (itemstack1.getCount() < i1) { + stack.shrink(i1 - itemstack1.getCount()); + itemstack1.setCount(i1); ++ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + slot.setChanged(); ++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + flag1 = true; + } + } +@@ -897,10 +914,21 @@ public abstract class AbstractContainerMenu { + + slot = (Slot) this.slots.get(k); + itemstack1 = slot.getItem(); ++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent ++ if (isCheck) { ++ itemstack1 = itemstack1.copy(); ++ } ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + if (itemstack1.isEmpty() && slot.mayPlace(stack)) { + l = slot.getMaxStackSize(stack); ++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent ++ if (isCheck) { ++ stack.shrink(Math.min(stack.getCount(), l)); ++ } else { ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + slot.setByPlayer(stack.split(Math.min(stack.getCount(), l))); + slot.setChanged(); ++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + flag1 = true; + break; + } +diff --git a/src/main/java/net/minecraft/world/inventory/MerchantMenu.java b/src/main/java/net/minecraft/world/inventory/MerchantMenu.java +index 90560dfad263d42432dc034a29930e6bab953b9a..6a529b5e289c416c0ebdc0260086ec039777aa40 100644 +--- a/src/main/java/net/minecraft/world/inventory/MerchantMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/MerchantMenu.java +@@ -123,12 +123,12 @@ public class MerchantMenu extends AbstractContainerMenu { + + itemstack = itemstack1.copy(); + if (slot == 2) { +- if (!this.moveItemStackTo(itemstack1, 3, 39, true)) { ++ if (!this.moveItemStackTo(itemstack1, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + return ItemStack.EMPTY; + } + +- slot1.onQuickCraft(itemstack1, itemstack); +- this.playTradeSound(); ++ // slot1.onQuickCraft(itemstack1, itemstack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call ++ // this.playTradeSound(); + } else if (slot != 0 && slot != 1) { + if (slot >= 3 && slot < 30) { + if (!this.moveItemStackTo(itemstack1, 30, 39, false)) { +@@ -141,6 +141,7 @@ public class MerchantMenu extends AbstractContainerMenu { + return ItemStack.EMPTY; + } + ++ if (slot != 2) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved down for slot 2 + if (itemstack1.isEmpty()) { + slot1.setByPlayer(ItemStack.EMPTY); + } else { +@@ -152,6 +153,21 @@ public class MerchantMenu extends AbstractContainerMenu { + } + + slot1.onTake(player, itemstack1); ++ } // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; handle slot 2 ++ if (slot == 2) { // is merchant result slot ++ slot1.onTake(player, itemstack1); ++ if (itemstack1.isEmpty()) { ++ slot1.set(ItemStack.EMPTY); ++ return ItemStack.EMPTY; ++ } ++ ++ this.moveItemStackTo(itemstack1, 3, 39, true, false); // This should always succeed because it's checked above ++ ++ slot1.onQuickCraft(itemstack1, itemstack); ++ this.playTradeSound(); ++ slot1.set(ItemStack.EMPTY); // itemstack1 should ALWAYS be empty ++ } ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + } + + return itemstack; +diff --git a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java +index 26227033613a641a9d5a6f29356b19e54753b3f1..c2376538215604210d08acd33e8e5fdc8a35c7d3 100644 +--- a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java ++++ b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java +@@ -47,13 +47,32 @@ public class MerchantResultSlot extends Slot { + + @Override + public void onTake(Player player, ItemStack stack) { +- this.checkTakeAchievements(stack); ++ // this.checkTakeAchievements(stack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; move to after event is called and not cancelled + MerchantOffer merchantOffer = this.slots.getActiveOffer(); ++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent ++ io.papermc.paper.event.player.PlayerPurchaseEvent event = null; ++ if (merchantOffer != null && player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ if (this.merchant instanceof net.minecraft.world.entity.npc.AbstractVillager abstractVillager) { ++ event = new io.papermc.paper.event.player.PlayerTradeEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.AbstractVillager) abstractVillager.getBukkitEntity(), merchantOffer.asBukkit(), true, true); ++ } else if (this.merchant instanceof org.bukkit.craftbukkit.inventory.CraftMerchantCustom.MinecraftMerchant) { ++ event = new io.papermc.paper.event.player.PlayerPurchaseEvent(serverPlayer.getBukkitEntity(), merchantOffer.asBukkit(), false, true); ++ } ++ if (event != null) { ++ if (!event.callEvent()) { ++ stack.setCount(0); ++ event.getPlayer().updateInventory(); ++ return; ++ } ++ merchantOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft(); ++ } ++ } ++ this.checkTakeAchievements(stack); ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + if (merchantOffer != null) { + ItemStack itemStack = this.slots.getItem(0); + ItemStack itemStack2 = this.slots.getItem(1); + if (merchantOffer.take(itemStack, itemStack2) || merchantOffer.take(itemStack2, itemStack)) { +- this.merchant.notifyTrade(merchantOffer); ++ this.merchant.processTrade(merchantOffer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + player.awardStat(Stats.TRADED_WITH_VILLAGER); + this.slots.setItem(0, itemStack); + this.slots.setItem(1, itemStack2); +diff --git a/src/main/java/net/minecraft/world/item/trading/Merchant.java b/src/main/java/net/minecraft/world/item/trading/Merchant.java +index 5a350948a4735902f5c612592bc9d100445a0c8a..716b30dcd7e63c66736c448dd136c9f74dc7fe43 100644 +--- a/src/main/java/net/minecraft/world/item/trading/Merchant.java ++++ b/src/main/java/net/minecraft/world/item/trading/Merchant.java +@@ -20,6 +20,7 @@ public interface Merchant { + + void overrideOffers(MerchantOffers offers); + ++ default void processTrade(MerchantOffer merchantRecipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { this.notifyTrade(merchantRecipe); } // Paper + void notifyTrade(MerchantOffer offer); + + void notifyTradeUpdated(ItemStack stack); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java +index ef47eb9a321a7b082413d3986d3d394afb899610..54debe9da0a26aea02c964fdc7efb372e07974c0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java +@@ -76,10 +76,25 @@ public class CraftMerchantCustom implements CraftMerchant { + return this.trades; + } + ++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent ++ @Override ++ public void processTrade(MerchantOffer merchantRecipe, @javax.annotation.Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent ++ /** Based on {@link net.minecraft.world.entity.npc.AbstractVillager#processTrade(MerchantOffer, io.papermc.paper.event.player.PlayerPurchaseEvent)} */ ++ if (getTradingPlayer() instanceof net.minecraft.server.level.ServerPlayer) { ++ if (event == null || event.willIncreaseTradeUses()) { ++ merchantRecipe.increaseUses(); ++ } ++ if (event == null || event.isRewardingExp()) { ++ this.tradingPlayer.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.tradingPlayer.level(), this.tradingPlayer.getX(), this.tradingPlayer.getY(), this.tradingPlayer.getZ(), merchantRecipe.getXp(), org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.tradingPlayer, null)); ++ } ++ } ++ this.notifyTrade(merchantRecipe); ++ } ++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + @Override + public void notifyTrade(MerchantOffer offer) { + // increase recipe's uses +- offer.increaseUses(); ++ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; handled above in processTrade + } + + @Override diff --git a/patches/server/0915-Reduce-allocation-of-Vec3D-by-entity-tracker.patch b/patches/server/0915-Reduce-allocation-of-Vec3D-by-entity-tracker.patch deleted file mode 100644 index 2fd7060c00..0000000000 --- a/patches/server/0915-Reduce-allocation-of-Vec3D-by-entity-tracker.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 27 Apr 2020 00:04:16 -0700 -Subject: [PATCH] Reduce allocation of Vec3D by entity tracker - - -diff --git a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java -index a043ac10834562d357ef0b5aded2e916e2a0d056..74276c368016fcc4dbf9579b2ecbadc9614baf15 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java -+++ b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java -@@ -5,7 +5,7 @@ import org.jetbrains.annotations.VisibleForTesting; - - public class VecDeltaCodec { - private static final double TRUNCATION_STEPS = 4096.0; -- private Vec3 base = Vec3.ZERO; -+ public Vec3 base = Vec3.ZERO; // Paper - - @VisibleForTesting - static long encode(double value) { -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 95c70de2c9f0e26742c0d66ad6c3bcc310a923f6..182513bb175feb5f30f0fb1cd5db501b6d483afd 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1578,10 +1578,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public void updatePlayer(ServerPlayer player) { - org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot - if (player != this.entity) { -- Vec3 vec3d = player.position().subtract(this.entity.position()); -+ // Paper start - remove allocation of Vec3D here -+ // Vec3 vec3d = player.position().subtract(this.entity.position()); -+ double vec3d_dx = player.getX() - this.entity.getX(); -+ double vec3d_dz = player.getZ() - this.entity.getZ(); -+ // Paper end - remove allocation of Vec3D here - int i = ChunkMap.this.getPlayerViewDistance(player); - double d0 = (double) Math.min(this.getEffectiveRange(), i * 16); -- double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; -+ double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper - double d2 = d0 * d0; - // Paper start - Configurable entity tracking range by Y - boolean flag = d1 <= d2; -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 7118e1f806af98159ec292f9340d7e4004e2b486..f3456aeeab7eee5b6d0383a4bf1338dd8cc95bb3 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -178,7 +178,13 @@ public class ServerEntity { - - ++this.teleportDelay; - Vec3 vec3d = this.entity.trackingPosition(); -- boolean flag1 = this.positionCodec.delta(vec3d).lengthSqr() >= 7.62939453125E-6D; -+ // Paper start - reduce allocation of Vec3D here -+ Vec3 base = this.positionCodec.base; -+ double vec3d_dx = vec3d.x - base.x; -+ double vec3d_dy = vec3d.y - base.y; -+ double vec3d_dz = vec3d.z - base.z; -+ boolean flag1 = (vec3d_dx * vec3d_dx + vec3d_dy * vec3d_dy + vec3d_dz * vec3d_dz) >= 7.62939453125E-6D; -+ // Paper end - reduce allocation of Vec3D here - Packet packet1 = null; - boolean flag2 = flag1 || this.tickCount % 60 == 0; - boolean flag3 = false; diff --git a/patches/server/0916-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch b/patches/server/0916-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch deleted file mode 100644 index 4ed1121ea1..0000000000 --- a/patches/server/0916-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 2 Jul 2020 16:12:10 -0700 -Subject: [PATCH] Add PlayerTradeEvent and PlayerPurchaseEvent - -Co-authored-by: Alexander - -diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -index 39cb40b077e9c07471437d5bec16ba9a7e6bce52..5f656fc726a1dc5f42657095a2f2b7cf85b92d7c 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -141,11 +141,24 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa - @Override - public void overrideXp(int experience) {} - -+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent -+ @Override -+ public void processTrade(MerchantOffer recipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent -+ if (event == null || event.willIncreaseTradeUses()) { -+ recipe.increaseUses(); -+ } -+ if (event == null || event.isRewardingExp()) { -+ this.rewardTradeXp(recipe); -+ } -+ this.notifyTrade(recipe); -+ } -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent -+ - @Override - public void notifyTrade(MerchantOffer offer) { -- offer.increaseUses(); -+ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - this.ambientSoundTime = -this.getAmbientSoundInterval(); -- this.rewardTradeXp(offer); -+ // this.rewardTradeXp(offer); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - if (this.tradingPlayer instanceof ServerPlayer) { - CriteriaTriggers.TRADE.trigger((ServerPlayer) this.tradingPlayer, this, offer.getResult()); - } -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index 85caec29a705f216eff8a5ae11f250697891a05c..78d0ff45c016e900d87010e8b26b0bb10e63f445 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -831,6 +831,14 @@ public abstract class AbstractContainerMenu { - public abstract boolean stillValid(Player player); - - protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast) { -+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent -+ return this.moveItemStackTo(stack, startIndex, endIndex, fromLast, false); -+ } -+ protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast, boolean isCheck) { -+ if (isCheck) { -+ stack = stack.copy(); -+ } -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - boolean flag1 = false; - int k = startIndex; - -@@ -854,6 +862,11 @@ public abstract class AbstractContainerMenu { - - slot = (Slot) this.slots.get(k); - itemstack1 = slot.getItem(); -+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; clone if only a check -+ if (isCheck) { -+ itemstack1 = itemstack1.copy(); -+ } -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - if (!itemstack1.isEmpty() && ItemStack.isSameItemSameComponents(stack, itemstack1)) { - l = itemstack1.getCount() + stack.getCount(); - int i1 = slot.getMaxStackSize(itemstack1); -@@ -861,12 +874,16 @@ public abstract class AbstractContainerMenu { - if (l <= i1) { - stack.setCount(0); - itemstack1.setCount(l); -+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - slot.setChanged(); -+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - flag1 = true; - } else if (itemstack1.getCount() < i1) { - stack.shrink(i1 - itemstack1.getCount()); - itemstack1.setCount(i1); -+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - slot.setChanged(); -+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - flag1 = true; - } - } -@@ -897,10 +914,21 @@ public abstract class AbstractContainerMenu { - - slot = (Slot) this.slots.get(k); - itemstack1 = slot.getItem(); -+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent -+ if (isCheck) { -+ itemstack1 = itemstack1.copy(); -+ } -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - if (itemstack1.isEmpty() && slot.mayPlace(stack)) { - l = slot.getMaxStackSize(stack); -+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent -+ if (isCheck) { -+ stack.shrink(Math.min(stack.getCount(), l)); -+ } else { -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - slot.setByPlayer(stack.split(Math.min(stack.getCount(), l))); - slot.setChanged(); -+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - flag1 = true; - break; - } -diff --git a/src/main/java/net/minecraft/world/inventory/MerchantMenu.java b/src/main/java/net/minecraft/world/inventory/MerchantMenu.java -index 90560dfad263d42432dc034a29930e6bab953b9a..6a529b5e289c416c0ebdc0260086ec039777aa40 100644 ---- a/src/main/java/net/minecraft/world/inventory/MerchantMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/MerchantMenu.java -@@ -123,12 +123,12 @@ public class MerchantMenu extends AbstractContainerMenu { - - itemstack = itemstack1.copy(); - if (slot == 2) { -- if (!this.moveItemStackTo(itemstack1, 3, 39, true)) { -+ if (!this.moveItemStackTo(itemstack1, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - return ItemStack.EMPTY; - } - -- slot1.onQuickCraft(itemstack1, itemstack); -- this.playTradeSound(); -+ // slot1.onQuickCraft(itemstack1, itemstack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call -+ // this.playTradeSound(); - } else if (slot != 0 && slot != 1) { - if (slot >= 3 && slot < 30) { - if (!this.moveItemStackTo(itemstack1, 30, 39, false)) { -@@ -141,6 +141,7 @@ public class MerchantMenu extends AbstractContainerMenu { - return ItemStack.EMPTY; - } - -+ if (slot != 2) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved down for slot 2 - if (itemstack1.isEmpty()) { - slot1.setByPlayer(ItemStack.EMPTY); - } else { -@@ -152,6 +153,21 @@ public class MerchantMenu extends AbstractContainerMenu { - } - - slot1.onTake(player, itemstack1); -+ } // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; handle slot 2 -+ if (slot == 2) { // is merchant result slot -+ slot1.onTake(player, itemstack1); -+ if (itemstack1.isEmpty()) { -+ slot1.set(ItemStack.EMPTY); -+ return ItemStack.EMPTY; -+ } -+ -+ this.moveItemStackTo(itemstack1, 3, 39, true, false); // This should always succeed because it's checked above -+ -+ slot1.onQuickCraft(itemstack1, itemstack); -+ this.playTradeSound(); -+ slot1.set(ItemStack.EMPTY); // itemstack1 should ALWAYS be empty -+ } -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - } - - return itemstack; -diff --git a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java -index 26227033613a641a9d5a6f29356b19e54753b3f1..c2376538215604210d08acd33e8e5fdc8a35c7d3 100644 ---- a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java -+++ b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java -@@ -47,13 +47,32 @@ public class MerchantResultSlot extends Slot { - - @Override - public void onTake(Player player, ItemStack stack) { -- this.checkTakeAchievements(stack); -+ // this.checkTakeAchievements(stack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; move to after event is called and not cancelled - MerchantOffer merchantOffer = this.slots.getActiveOffer(); -+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent -+ io.papermc.paper.event.player.PlayerPurchaseEvent event = null; -+ if (merchantOffer != null && player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { -+ if (this.merchant instanceof net.minecraft.world.entity.npc.AbstractVillager abstractVillager) { -+ event = new io.papermc.paper.event.player.PlayerTradeEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.AbstractVillager) abstractVillager.getBukkitEntity(), merchantOffer.asBukkit(), true, true); -+ } else if (this.merchant instanceof org.bukkit.craftbukkit.inventory.CraftMerchantCustom.MinecraftMerchant) { -+ event = new io.papermc.paper.event.player.PlayerPurchaseEvent(serverPlayer.getBukkitEntity(), merchantOffer.asBukkit(), false, true); -+ } -+ if (event != null) { -+ if (!event.callEvent()) { -+ stack.setCount(0); -+ event.getPlayer().updateInventory(); -+ return; -+ } -+ merchantOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft(); -+ } -+ } -+ this.checkTakeAchievements(stack); -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - if (merchantOffer != null) { - ItemStack itemStack = this.slots.getItem(0); - ItemStack itemStack2 = this.slots.getItem(1); - if (merchantOffer.take(itemStack, itemStack2) || merchantOffer.take(itemStack2, itemStack)) { -- this.merchant.notifyTrade(merchantOffer); -+ this.merchant.processTrade(merchantOffer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - player.awardStat(Stats.TRADED_WITH_VILLAGER); - this.slots.setItem(0, itemStack); - this.slots.setItem(1, itemStack2); -diff --git a/src/main/java/net/minecraft/world/item/trading/Merchant.java b/src/main/java/net/minecraft/world/item/trading/Merchant.java -index 5a350948a4735902f5c612592bc9d100445a0c8a..716b30dcd7e63c66736c448dd136c9f74dc7fe43 100644 ---- a/src/main/java/net/minecraft/world/item/trading/Merchant.java -+++ b/src/main/java/net/minecraft/world/item/trading/Merchant.java -@@ -20,6 +20,7 @@ public interface Merchant { - - void overrideOffers(MerchantOffers offers); - -+ default void processTrade(MerchantOffer merchantRecipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { this.notifyTrade(merchantRecipe); } // Paper - void notifyTrade(MerchantOffer offer); - - void notifyTradeUpdated(ItemStack stack); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java -index ef47eb9a321a7b082413d3986d3d394afb899610..54debe9da0a26aea02c964fdc7efb372e07974c0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java -@@ -76,10 +76,25 @@ public class CraftMerchantCustom implements CraftMerchant { - return this.trades; - } - -+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent -+ @Override -+ public void processTrade(MerchantOffer merchantRecipe, @javax.annotation.Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent -+ /** Based on {@link net.minecraft.world.entity.npc.AbstractVillager#processTrade(MerchantOffer, io.papermc.paper.event.player.PlayerPurchaseEvent)} */ -+ if (getTradingPlayer() instanceof net.minecraft.server.level.ServerPlayer) { -+ if (event == null || event.willIncreaseTradeUses()) { -+ merchantRecipe.increaseUses(); -+ } -+ if (event == null || event.isRewardingExp()) { -+ this.tradingPlayer.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.tradingPlayer.level(), this.tradingPlayer.getX(), this.tradingPlayer.getY(), this.tradingPlayer.getZ(), merchantRecipe.getXp(), org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.tradingPlayer, null)); -+ } -+ } -+ this.notifyTrade(merchantRecipe); -+ } -+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - @Override - public void notifyTrade(MerchantOffer offer) { - // increase recipe's uses -- offer.increaseUses(); -+ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; handled above in processTrade - } - - @Override diff --git a/patches/server/0916-Add-ShulkerDuplicateEvent.patch b/patches/server/0916-Add-ShulkerDuplicateEvent.patch new file mode 100644 index 0000000000..f06c91ae48 --- /dev/null +++ b/patches/server/0916-Add-ShulkerDuplicateEvent.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chase Henderson +Date: Fri, 5 Jan 2024 03:50:10 -0500 +Subject: [PATCH] Add ShulkerDuplicateEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java +index 0fffa9dbcbbb15a2138f9a4e4d8e812c8047a7bb..6e0f2f6573ed6be9b91de960d55c269417ad8907 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java +@@ -492,6 +492,11 @@ public class Shulker extends AbstractGolem implements VariantHolder -Date: Fri, 5 Jan 2024 03:50:10 -0500 -Subject: [PATCH] Add ShulkerDuplicateEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index 0fffa9dbcbbb15a2138f9a4e4d8e812c8047a7bb..6e0f2f6573ed6be9b91de960d55c269417ad8907 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -492,6 +492,11 @@ public class Shulker extends AbstractGolem implements VariantHolder +Date: Thu, 11 Jan 2024 19:58:23 +0100 +Subject: [PATCH] Add api for spawn egg texture colors + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 1835f8cfda0222fadd9db31abfb7e85899051853..30106a999db1bae217333b5e94913b9ec55e4615 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -629,6 +629,15 @@ public final class CraftMagicNumbers implements UnsafeValues { + } + // Paper end + ++ // Paper start - spawn egg color visibility ++ @Override ++ public org.bukkit.Color getSpawnEggLayerColor(final EntityType entityType, final int layer) { ++ final net.minecraft.world.entity.EntityType nmsType = org.bukkit.craftbukkit.entity.CraftEntityType.bukkitToMinecraft(entityType); ++ final net.minecraft.world.item.SpawnEggItem eggItem = net.minecraft.world.item.SpawnEggItem.byId(nmsType); ++ return eggItem == null ? null : org.bukkit.Color.fromRGB(eggItem.getColor(layer)); ++ } ++ // Paper end - spawn egg color visibility ++ + /** + * This helper class represents the different NBT Tags. + *

diff --git a/patches/server/0918-Add-Lifecycle-Event-system.patch b/patches/server/0918-Add-Lifecycle-Event-system.patch new file mode 100644 index 0000000000..0eaff54d34 --- /dev/null +++ b/patches/server/0918-Add-Lifecycle-Event-system.patch @@ -0,0 +1,785 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 18 Jul 2023 17:49:38 -0700 +Subject: [PATCH] Add Lifecycle Event system + +This event system is separate from Bukkit's event system and is +meant for managing resources across reloads and from points in the +PluginBootstrap. + +diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java +index 30b50e6294c6eaade5e17cfaf34600d122e6251c..0bb7694188d5fb75bb756ce75d0060ea980027ee 100644 +--- a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java ++++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java +@@ -1,6 +1,8 @@ + package io.papermc.paper.plugin.bootstrap; + + import io.papermc.paper.plugin.configuration.PluginMeta; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; ++import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEventManager; + import io.papermc.paper.plugin.provider.PluginProvider; + import java.nio.file.Path; + import net.kyori.adventure.text.logger.slf4j.ComponentLogger; +@@ -12,6 +14,10 @@ public final class PluginBootstrapContextImpl implements BootstrapContext { + private final Path dataFolder; + private final ComponentLogger logger; + private final Path pluginSource; ++ // Paper start - lifecycle events ++ private boolean allowsLifecycleRegistration = true; ++ private final PaperLifecycleEventManager lifecycleEventManager = new PaperLifecycleEventManager<>(this, () -> this.allowsLifecycleRegistration); // Paper - lifecycle events ++ // Paper end - lifecycle events + + public PluginBootstrapContextImpl(PluginMeta config, Path dataFolder, ComponentLogger logger, Path pluginSource) { + this.config = config; +@@ -45,4 +51,20 @@ public final class PluginBootstrapContextImpl implements BootstrapContext { + public @NotNull Path getPluginSource() { + return this.pluginSource; + } ++ ++ // Paper start - lifecycle event system ++ @Override ++ public @NotNull PluginMeta getPluginMeta() { ++ return this.config; ++ } ++ ++ @Override ++ public LifecycleEventManager getLifecycleManager() { ++ return this.lifecycleEventManager; ++ } ++ ++ public void lockLifecycleEventRegistration() { ++ this.allowsLifecycleRegistration = false; ++ } ++ // Paper end + } +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ce808520d639581696689a2ab85de00d85aa0ee3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java +@@ -0,0 +1,100 @@ ++package io.papermc.paper.plugin.lifecycle.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar; ++import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEvent; ++import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEventImpl; ++import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent; ++import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.plugin.lifecycle.event.types.OwnerAwareLifecycleEvent; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.function.Predicate; ++import org.bukkit.plugin.Plugin; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class LifecycleEventRunner { ++ ++ public static final LifecycleEventRunner INSTANCE = new LifecycleEventRunner(); ++ ++ private final List> lifecycleEventTypes = new ArrayList<>(); ++ private boolean blockPluginReloading = false; ++ ++ public void checkRegisteredHandler(final O owner, final AbstractLifecycleEventType eventType) { ++ /* ++ Lifecycle event handlers for reloadable events that are registered from the BootstrapContext prevent ++ the server from reloading plugins. This is because reloading plugins requires disabling all the plugins, ++ running the reload logic (which would include places where these events should fire) and then re-enabling plugins. ++ */ ++ if (eventType.blocksReloading(owner)) { ++ this.blockPluginReloading = true; ++ } ++ } ++ ++ public boolean blocksPluginReloading() { ++ return this.blockPluginReloading; ++ } ++ ++ public > void addEventType(final ET eventType) { ++ this.lifecycleEventTypes.add(eventType); ++ } ++ ++ public void callEvent(final LifecycleEventType eventType, final E event) { ++ this.callEvent(eventType, event, $ -> true); ++ } ++ ++ public void callEvent(final LifecycleEventType eventType, final E event, final Predicate ownerPredicate) { ++ final AbstractLifecycleEventType lifecycleEventType = (AbstractLifecycleEventType) eventType; ++ lifecycleEventType.forEachHandler(event, registeredHandler -> { ++ try { ++ if (event instanceof final OwnerAwareLifecycleEvent ownerAwareEvent) { ++ ownerAwareGenericHelper(ownerAwareEvent, registeredHandler.owner()); ++ } ++ registeredHandler.lifecycleEventHandler().run(event); ++ } catch (final Throwable ex) { ++ throw new RuntimeException("Could not run '%s' lifecycle event handler from %s".formatted(lifecycleEventType.name(), registeredHandler.owner().getPluginMeta().getDisplayName()), ex); ++ } finally { ++ if (event instanceof final OwnerAwareLifecycleEvent ownerAwareEvent) { ++ ownerAwareEvent.setOwner(null); ++ } ++ } ++ }, handler -> ownerPredicate.test(handler.owner())); ++ event.invalidate(); ++ } ++ ++ private static void ownerAwareGenericHelper(final OwnerAwareLifecycleEvent event, final LifecycleEventOwner possibleOwner) { ++ final @Nullable O owner = event.castOwner(possibleOwner); ++ if (owner != null) { ++ event.setOwner(owner); ++ } else { ++ throw new IllegalStateException("Found invalid owner " + possibleOwner + " for event " + event); ++ } ++ } ++ ++ public void unregisterAllEventHandlersFor(final Plugin plugin) { ++ for (final LifecycleEventType lifecycleEventType : this.lifecycleEventTypes) { ++ this.removeEventHandlersOwnedBy(lifecycleEventType, plugin); ++ } ++ } ++ ++ private void removeEventHandlersOwnedBy(final LifecycleEventType eventType, final Plugin possibleOwner) { ++ final AbstractLifecycleEventType lifecycleEventType = (AbstractLifecycleEventType) eventType; ++ lifecycleEventType.removeMatching(registeredHandler -> registeredHandler.owner().getPluginMeta().getName().equals(possibleOwner.getPluginMeta().getName())); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public > void callStaticRegistrarEvent(final LifecycleEventType, ?> lifecycleEventType, final R registrar, final Class ownerClass) { ++ this.callEvent((LifecycleEventType, ?>) lifecycleEventType, new RegistrarEventImpl<>(registrar, ownerClass), ownerClass::isInstance); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public > void callReloadableRegistrarEvent(final LifecycleEventType, ?> lifecycleEventType, final R registrar, final Class ownerClass, final ReloadableRegistrarEvent.Cause cause) { ++ this.callEvent((LifecycleEventType, ?>) lifecycleEventType, new RegistrarEventImpl.ReloadableImpl<>(registrar, ownerClass, cause), ownerClass::isInstance); ++ } ++ ++ private LifecycleEventRunner() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e941405269a773e8a77e26ffd1afd84f53fadff5 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java +@@ -0,0 +1,10 @@ ++package io.papermc.paper.plugin.lifecycle.event; ++ ++public interface PaperLifecycleEvent extends LifecycleEvent { ++ ++ // called after all handlers have been run. Can be ++ // used to invalid various contexts to plugins can't ++ // try to re-use them by storing them from the event ++ default void invalidate() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d05334016bd01201c755dea04c0cea56b6dfcb50 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.plugin.lifecycle.event; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; ++import java.util.function.BooleanSupplier; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public final class PaperLifecycleEventManager implements LifecycleEventManager { ++ ++ private final O owner; ++ public final BooleanSupplier registrationCheck; ++ ++ public PaperLifecycleEventManager(final O owner, final BooleanSupplier registrationCheck) { ++ this.owner = owner; ++ this.registrationCheck = registrationCheck; ++ } ++ ++ @Override ++ public void registerEventHandler(final LifecycleEventHandlerConfiguration handlerConfiguration) { ++ Preconditions.checkState(this.registrationCheck.getAsBoolean(), "Cannot register lifecycle event handlers"); ++ ((AbstractLifecycleEventHandlerConfiguration) handlerConfiguration).registerFrom(this.owner); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fa216e6fd804859293385ed43c53dfca057f317f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.plugin.lifecycle.event.handler.configuration; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public abstract class AbstractLifecycleEventHandlerConfiguration implements LifecycleEventHandlerConfiguration { ++ ++ private final LifecycleEventHandler handler; ++ private final AbstractLifecycleEventType type; ++ ++ protected AbstractLifecycleEventHandlerConfiguration(final LifecycleEventHandler handler, final AbstractLifecycleEventType type) { ++ this.handler = handler; ++ this.type = type; ++ } ++ ++ public final void registerFrom(final O owner) { ++ this.type.tryRegister(owner, this); ++ } ++ ++ public LifecycleEventHandler handler() { ++ return this.handler; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ab444d60d72bd692843052df5d7b24fbb5621cf7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.plugin.lifecycle.event.handler.configuration; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class MonitorLifecycleEventHandlerConfigurationImpl extends AbstractLifecycleEventHandlerConfiguration implements MonitorLifecycleEventHandlerConfiguration { ++ ++ private boolean monitor = false; ++ ++ public MonitorLifecycleEventHandlerConfigurationImpl(final LifecycleEventHandler handler, final AbstractLifecycleEventType eventType) { ++ super(handler, eventType); ++ } ++ ++ public boolean isMonitor() { ++ return this.monitor; ++ } ++ ++ @Override ++ public MonitorLifecycleEventHandlerConfiguration monitor() { ++ this.monitor = true; ++ return this; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ccdad31717bf12b844cbeaf11a49247485ec77f1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.plugin.lifecycle.event.handler.configuration; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; ++import java.util.OptionalInt; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class PrioritizedLifecycleEventHandlerConfigurationImpl ++ extends AbstractLifecycleEventHandlerConfiguration ++ implements PrioritizedLifecycleEventHandlerConfiguration { ++ ++ private static final OptionalInt DEFAULT_PRIORITY = OptionalInt.of(0); ++ private static final OptionalInt MONITOR_PRIORITY = OptionalInt.empty(); ++ ++ private OptionalInt priority = DEFAULT_PRIORITY; ++ ++ public PrioritizedLifecycleEventHandlerConfigurationImpl(final LifecycleEventHandler handler, final AbstractLifecycleEventType eventType) { ++ super(handler, eventType); ++ } ++ ++ public OptionalInt priority() { ++ return this.priority; ++ } ++ ++ @Override ++ public PrioritizedLifecycleEventHandlerConfiguration priority(final int priority) { ++ this.priority = OptionalInt.of(priority); ++ return this; ++ } ++ ++ @Override ++ public PrioritizedLifecycleEventHandlerConfiguration monitor() { ++ this.priority = MONITOR_PRIORITY; ++ return this; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b2586c881988fbabe07eef1b43eb1b55f2d3fa52 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java +@@ -0,0 +1,15 @@ ++package io.papermc.paper.plugin.lifecycle.event.registrar; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public interface PaperRegistrar extends Registrar { ++ ++ void setCurrentContext(@Nullable O owner); ++ ++ default void invalidate() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6d530c52aaf0dc2cdfe3bd56af557274a7f44256 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java +@@ -0,0 +1,70 @@ ++package io.papermc.paper.plugin.lifecycle.event.registrar; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.types.OwnerAwareLifecycleEvent; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class RegistrarEventImpl, O extends LifecycleEventOwner> implements PaperLifecycleEvent, OwnerAwareLifecycleEvent, RegistrarEvent { ++ ++ private final R registrar; ++ private final Class ownerClass; ++ ++ public RegistrarEventImpl(final R registrar, final Class ownerClass) { ++ this.registrar = registrar; ++ this.ownerClass = ownerClass; ++ } ++ ++ @Override ++ public R registrar() { ++ return this.registrar; ++ } ++ ++ @Override ++ public final void setOwner(final @Nullable O owner) { ++ this.registrar.setCurrentContext(owner); ++ } ++ ++ @Override ++ public final @Nullable O castOwner(final LifecycleEventOwner owner) { ++ return this.ownerClass.isInstance(owner) ? this.ownerClass.cast(owner) : null; ++ } ++ ++ @Override ++ public void invalidate() { ++ this.registrar.invalidate(); ++ } ++ ++ @Override ++ public String toString() { ++ return "RegistrarEventImpl{" + ++ "registrar=" + this.registrar + ++ ", ownerClass=" + this.ownerClass + ++ '}'; ++ } ++ ++ public static class ReloadableImpl, O extends LifecycleEventOwner> extends RegistrarEventImpl implements ReloadableRegistrarEvent { ++ ++ private final ReloadableRegistrarEvent.Cause cause; ++ ++ public ReloadableImpl(final R registrar, final Class ownerClass, final Cause cause) { ++ super(registrar, ownerClass); ++ this.cause = cause; ++ } ++ ++ @Override ++ public Cause cause() { ++ return this.cause; ++ } ++ ++ @Override ++ public String toString() { ++ return "ReloadableImpl{" + ++ "cause=" + this.cause + ++ "} " + super.toString(); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01a4e9a36a9970f30ed9f9236fc5a4a1cf71844e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java +@@ -0,0 +1,62 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; ++import java.util.function.Consumer; ++import java.util.function.Predicate; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public abstract class AbstractLifecycleEventType> implements LifecycleEventType { ++ ++ private final String name; ++ private final Class ownerType; ++ ++ protected AbstractLifecycleEventType(final String name, final Class ownerType) { ++ this.name = name; ++ this.ownerType = ownerType; ++ LifecycleEventRunner.INSTANCE.addEventType(this); ++ } ++ ++ @Override ++ public String name() { ++ return this.name; ++ } ++ ++ private void verifyOwner(final O owner) { ++ if (!this.ownerType.isInstance(owner)) { ++ throw new IllegalArgumentException("You cannot register the lifecycle event '" + this.name + "' on " + owner); ++ } ++ } ++ ++ public boolean blocksReloading(final O eventOwner) { ++ return eventOwner instanceof BootstrapContext; ++ } ++ ++ public abstract boolean hasHandlers(); ++ ++ public abstract void forEachHandler(E event, Consumer> consumer, Predicate> predicate); ++ ++ public abstract void removeMatching(Predicate> predicate); ++ ++ protected abstract void register(O owner, AbstractLifecycleEventHandlerConfiguration config); ++ ++ public final void tryRegister(final O owner, final AbstractLifecycleEventHandlerConfiguration config) { ++ this.verifyOwner(owner); ++ LifecycleEventRunner.INSTANCE.checkRegisteredHandler(owner, this); ++ this.register(owner, config); ++ } ++ ++ public record RegisteredHandler(O owner, AbstractLifecycleEventHandlerConfiguration config) { ++ ++ public LifecycleEventHandler lifecycleEventHandler() { ++ return this.config().handler(); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b11346e04bb16c3238f32deb87dbd680e261d4d2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public final class LifecycleEventTypeProviderImpl implements LifecycleEventTypeProvider { ++ ++ public static LifecycleEventTypeProviderImpl instance() { ++ return (LifecycleEventTypeProviderImpl) LifecycleEventTypeProvider.provider(); ++ } ++ ++ @Override ++ public LifecycleEventType.Monitorable monitor(final String name, final Class ownerType) { ++ return new MonitorableLifecycleEventType<>(name, ownerType); ++ } ++ ++ @Override ++ public LifecycleEventType.Prioritizable prioritized(final String name, final Class ownerType) { ++ return new PrioritizableLifecycleEventType.Simple<>(name, ownerType); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..abb969cf6ed967fe7720c56d3b3157bd1b74700d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java +@@ -0,0 +1,63 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.MonitorLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.MonitorLifecycleEventHandlerConfigurationImpl; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.function.Consumer; ++import java.util.function.Predicate; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class MonitorableLifecycleEventType extends AbstractLifecycleEventType> implements LifecycleEventType.Monitorable { ++ ++ final List> handlers = new ArrayList<>(); ++ int nonMonitorIdx = 0; ++ ++ public MonitorableLifecycleEventType(final String name, final Class ownerType) { ++ super(name, ownerType); ++ } ++ ++ @Override ++ public boolean hasHandlers() { ++ return !this.handlers.isEmpty(); ++ } ++ ++ @Override ++ public MonitorLifecycleEventHandlerConfigurationImpl newHandler(final LifecycleEventHandler handler) { ++ return new MonitorLifecycleEventHandlerConfigurationImpl<>(handler, this); ++ } ++ ++ @Override ++ protected void register(final O owner, final AbstractLifecycleEventHandlerConfiguration config) { ++ if (!(config instanceof final MonitorLifecycleEventHandlerConfigurationImpl monitor)) { ++ throw new IllegalArgumentException("Configuration must be a MonitorLifecycleEventHandlerConfiguration"); ++ } ++ final RegisteredHandler registeredHandler = new RegisteredHandler<>(owner, config); ++ if (!monitor.isMonitor()) { ++ this.handlers.add(this.nonMonitorIdx, registeredHandler); ++ this.nonMonitorIdx++; ++ } else { ++ this.handlers.add(registeredHandler); ++ } ++ } ++ ++ @Override ++ public void forEachHandler(final E event, final Consumer> consumer, final Predicate> predicate) { ++ for (final RegisteredHandler handler : this.handlers) { ++ if (predicate.test(handler)) { ++ consumer.accept(handler); ++ } ++ } ++ } ++ ++ @Override ++ public void removeMatching(final Predicate> predicate) { ++ this.handlers.removeIf(predicate); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3e7e7474f301c0725fa2bcd6e19e476fc35f2d5a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java +@@ -0,0 +1,15 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public interface OwnerAwareLifecycleEvent extends LifecycleEvent { ++ ++ void setOwner(@Nullable O owner); ++ ++ @Nullable O castOwner(LifecycleEventOwner owner); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2ed622a61ddc37b11888867770b513909b9a2ecc +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java +@@ -0,0 +1,79 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfigurationImpl; ++import java.util.ArrayList; ++import java.util.Comparator; ++import java.util.List; ++import java.util.function.Consumer; ++import java.util.function.Predicate; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public abstract class PrioritizableLifecycleEventType< ++ O extends LifecycleEventOwner, ++ E extends LifecycleEvent, ++ C extends PrioritizedLifecycleEventHandlerConfiguration ++> extends AbstractLifecycleEventType { ++ ++ private static final Comparator> COMPARATOR = Comparator.comparing(handler -> ((PrioritizedLifecycleEventHandlerConfigurationImpl) handler.config()).priority(), (o1, o2) -> { ++ if (o1.equals(o2)) { ++ return 0; ++ } else if (o1.isEmpty()) { ++ return 1; ++ } else if (o2.isEmpty()) { ++ return -1; ++ } else { ++ return Integer.compare(o1.getAsInt(), o2.getAsInt()); ++ } ++ }); ++ ++ private final List> handlers = new ArrayList<>(); ++ ++ public PrioritizableLifecycleEventType(final String name, final Class ownerType) { ++ super(name, ownerType); ++ } ++ ++ @Override ++ public boolean hasHandlers() { ++ return !this.handlers.isEmpty(); ++ } ++ ++ @Override ++ protected void register(final O owner, final AbstractLifecycleEventHandlerConfiguration config) { ++ Preconditions.checkArgument(config instanceof PrioritizedLifecycleEventHandlerConfigurationImpl, "Configuration must be a PrioritizedLifecycleEventHandlerConfiguration"); ++ this.handlers.add(new RegisteredHandler<>(owner, config)); ++ this.handlers.sort(COMPARATOR); ++ } ++ ++ @Override ++ public void forEachHandler(final E event, final Consumer> consumer, final Predicate> predicate) { ++ for (final RegisteredHandler handler : this.handlers) { ++ if (predicate.test(handler)) { ++ consumer.accept(handler); ++ } ++ } ++ } ++ ++ @Override ++ public void removeMatching(final Predicate> predicate) { ++ this.handlers.removeIf(predicate); ++ } ++ ++ public static class Simple extends PrioritizableLifecycleEventType> implements LifecycleEventType.Prioritizable { ++ public Simple(final String name, final Class ownerType) { ++ super(name, ownerType); ++ } ++ ++ @Override ++ public PrioritizedLifecycleEventHandlerConfiguration newHandler(final LifecycleEventHandler handler) { ++ return new PrioritizedLifecycleEventHandlerConfigurationImpl<>(handler, this); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java +index 834b85f24df023642f8abf7213fe578ac8c17a3e..3e82ea07ca4194844c5528446e2c4a46ff4acee5 100644 +--- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java ++++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java +@@ -293,6 +293,15 @@ class PaperPluginInstanceManager { + + pluginName + " (Is it up to date?)", ex, plugin); // Paper + } + ++ // Paper start - lifecycle event system ++ try { ++ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.unregisterAllEventHandlersFor(plugin); ++ } catch (Throwable ex) { ++ this.handlePluginException("Error occurred (in the plugin loader) while unregistering lifecycle event handlers for " ++ + pluginName + " (Is it up to date?)", ex, plugin); ++ } ++ // Paper end ++ + try { + this.server.getMessenger().unregisterIncomingPluginChannel(plugin); + this.server.getMessenger().unregisterOutgoingPluginChannel(plugin); +diff --git a/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java b/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java +index 2e96308696e131f3f013469a395e5ddda2c5d529..65a66e484c1c39c5f41d97db52f31c67b4479d20 100644 +--- a/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java ++++ b/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java +@@ -32,8 +32,9 @@ public class BootstrapProviderStorage extends SimpleProviderStorage provider, PluginBootstrap provided) { + try { +- BootstrapContext context = PluginBootstrapContextImpl.create(provider, PluginInitializerManager.instance().pluginDirectoryPath()); ++ PluginBootstrapContextImpl context = PluginBootstrapContextImpl.create(provider, PluginInitializerManager.instance().pluginDirectoryPath()); // Paper - lifecycle events + provided.bootstrap(context); ++ context.lockLifecycleEventRegistration(); // Paper - lifecycle events + return true; + } catch (Throwable e) { + LOGGER.error("Failed to run bootstrapper for %s. This plugin will not be loaded.".formatted(provider.getSource()), e); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index a1f2c8fd0348a6a5dad521430f473867bdadd1a5..a2c749b2997557fec5c978f3bed8c35d7614e740 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1050,6 +1050,11 @@ public final class CraftServer implements Server { + + @Override + public void reload() { ++ // Paper start - lifecycle events ++ if (io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.blocksPluginReloading()) { ++ throw new IllegalStateException("A lifecycle event handler has been registered which makes reloading plugins not possible"); ++ } ++ // Paper end - lifecycle events + org.spigotmc.WatchdogThread.hasStarted = false; // Paper - Disable watchdog early timeout on reload + this.reloadCount++; + this.configuration = YamlConfiguration.loadConfiguration(this.getConfigFile()); +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 30106a999db1bae217333b5e94913b9ec55e4615..06d66c8043daec3c736d82d972ceb98d55eae9d1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -638,6 +638,13 @@ public final class CraftMagicNumbers implements UnsafeValues { + } + // Paper end - spawn egg color visibility + ++ // Paper start - lifecycle event API ++ @Override ++ public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck) { ++ return new io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEventManager<>(plugin, registrationCheck); ++ } ++ // Paper end - lifecycle event API ++ + /** + * This helper class represents the different NBT Tags. + *

+diff --git a/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider +new file mode 100644 +index 0000000000000000000000000000000000000000..808b1192b60348ad05f0bfbdeda6f94df4876743 +--- /dev/null ++++ b/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider +@@ -0,0 +1 @@ ++io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProviderImpl +diff --git a/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java b/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java +index 1d14f530ef888102e47eeeaf0d1a6076e51871c4..90cf0c702ca2ff9de64d9718ecba5f2d128953a6 100644 +--- a/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java ++++ b/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java +@@ -143,4 +143,11 @@ public class PaperTestPlugin extends PluginBase { + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + throw new UnsupportedOperationException("Not supported."); + } ++ ++ // Paper start - lifecycle events ++ @Override ++ public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager getLifecycleManager() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ // Paper end - lifecycle events + } diff --git a/patches/server/0918-Add-api-for-spawn-egg-texture-colors.patch b/patches/server/0918-Add-api-for-spawn-egg-texture-colors.patch deleted file mode 100644 index ee55eb2e4a..0000000000 --- a/patches/server/0918-Add-api-for-spawn-egg-texture-colors.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Luis -Date: Thu, 11 Jan 2024 19:58:23 +0100 -Subject: [PATCH] Add api for spawn egg texture colors - - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 3900f95f3ea41b010b8ea79c043fe322fa233461..7ae4567bc6f2f0374d1a4a3859f6329eaace7415 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -643,6 +643,15 @@ public final class CraftMagicNumbers implements UnsafeValues { - return CraftRegistry.get(registry, namespacedKey, ApiVersion.CURRENT); - } - -+ // Paper start - spawn egg color visibility -+ @Override -+ public org.bukkit.Color getSpawnEggLayerColor(final EntityType entityType, final int layer) { -+ final net.minecraft.world.entity.EntityType nmsType = org.bukkit.craftbukkit.entity.CraftEntityType.bukkitToMinecraft(entityType); -+ final net.minecraft.world.item.SpawnEggItem eggItem = net.minecraft.world.item.SpawnEggItem.byId(nmsType); -+ return eggItem == null ? null : org.bukkit.Color.fromRGB(eggItem.getColor(layer)); -+ } -+ // Paper end - spawn egg color visibility -+ - /** - * This helper class represents the different NBT Tags. - *

diff --git a/patches/server/0919-Add-Lifecycle-Event-system.patch b/patches/server/0919-Add-Lifecycle-Event-system.patch deleted file mode 100644 index 611ac65850..0000000000 --- a/patches/server/0919-Add-Lifecycle-Event-system.patch +++ /dev/null @@ -1,785 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 18 Jul 2023 17:49:38 -0700 -Subject: [PATCH] Add Lifecycle Event system - -This event system is separate from Bukkit's event system and is -meant for managing resources across reloads and from points in the -PluginBootstrap. - -diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java -index 30b50e6294c6eaade5e17cfaf34600d122e6251c..0bb7694188d5fb75bb756ce75d0060ea980027ee 100644 ---- a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java -+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java -@@ -1,6 +1,8 @@ - package io.papermc.paper.plugin.bootstrap; - - import io.papermc.paper.plugin.configuration.PluginMeta; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; -+import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEventManager; - import io.papermc.paper.plugin.provider.PluginProvider; - import java.nio.file.Path; - import net.kyori.adventure.text.logger.slf4j.ComponentLogger; -@@ -12,6 +14,10 @@ public final class PluginBootstrapContextImpl implements BootstrapContext { - private final Path dataFolder; - private final ComponentLogger logger; - private final Path pluginSource; -+ // Paper start - lifecycle events -+ private boolean allowsLifecycleRegistration = true; -+ private final PaperLifecycleEventManager lifecycleEventManager = new PaperLifecycleEventManager<>(this, () -> this.allowsLifecycleRegistration); // Paper - lifecycle events -+ // Paper end - lifecycle events - - public PluginBootstrapContextImpl(PluginMeta config, Path dataFolder, ComponentLogger logger, Path pluginSource) { - this.config = config; -@@ -45,4 +51,20 @@ public final class PluginBootstrapContextImpl implements BootstrapContext { - public @NotNull Path getPluginSource() { - return this.pluginSource; - } -+ -+ // Paper start - lifecycle event system -+ @Override -+ public @NotNull PluginMeta getPluginMeta() { -+ return this.config; -+ } -+ -+ @Override -+ public LifecycleEventManager getLifecycleManager() { -+ return this.lifecycleEventManager; -+ } -+ -+ public void lockLifecycleEventRegistration() { -+ this.allowsLifecycleRegistration = false; -+ } -+ // Paper end - } -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ce808520d639581696689a2ab85de00d85aa0ee3 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java -@@ -0,0 +1,100 @@ -+package io.papermc.paper.plugin.lifecycle.event; -+ -+import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar; -+import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEvent; -+import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEventImpl; -+import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent; -+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.plugin.lifecycle.event.types.OwnerAwareLifecycleEvent; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.function.Predicate; -+import org.bukkit.plugin.Plugin; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public class LifecycleEventRunner { -+ -+ public static final LifecycleEventRunner INSTANCE = new LifecycleEventRunner(); -+ -+ private final List> lifecycleEventTypes = new ArrayList<>(); -+ private boolean blockPluginReloading = false; -+ -+ public void checkRegisteredHandler(final O owner, final AbstractLifecycleEventType eventType) { -+ /* -+ Lifecycle event handlers for reloadable events that are registered from the BootstrapContext prevent -+ the server from reloading plugins. This is because reloading plugins requires disabling all the plugins, -+ running the reload logic (which would include places where these events should fire) and then re-enabling plugins. -+ */ -+ if (eventType.blocksReloading(owner)) { -+ this.blockPluginReloading = true; -+ } -+ } -+ -+ public boolean blocksPluginReloading() { -+ return this.blockPluginReloading; -+ } -+ -+ public > void addEventType(final ET eventType) { -+ this.lifecycleEventTypes.add(eventType); -+ } -+ -+ public void callEvent(final LifecycleEventType eventType, final E event) { -+ this.callEvent(eventType, event, $ -> true); -+ } -+ -+ public void callEvent(final LifecycleEventType eventType, final E event, final Predicate ownerPredicate) { -+ final AbstractLifecycleEventType lifecycleEventType = (AbstractLifecycleEventType) eventType; -+ lifecycleEventType.forEachHandler(event, registeredHandler -> { -+ try { -+ if (event instanceof final OwnerAwareLifecycleEvent ownerAwareEvent) { -+ ownerAwareGenericHelper(ownerAwareEvent, registeredHandler.owner()); -+ } -+ registeredHandler.lifecycleEventHandler().run(event); -+ } catch (final Throwable ex) { -+ throw new RuntimeException("Could not run '%s' lifecycle event handler from %s".formatted(lifecycleEventType.name(), registeredHandler.owner().getPluginMeta().getDisplayName()), ex); -+ } finally { -+ if (event instanceof final OwnerAwareLifecycleEvent ownerAwareEvent) { -+ ownerAwareEvent.setOwner(null); -+ } -+ } -+ }, handler -> ownerPredicate.test(handler.owner())); -+ event.invalidate(); -+ } -+ -+ private static void ownerAwareGenericHelper(final OwnerAwareLifecycleEvent event, final LifecycleEventOwner possibleOwner) { -+ final @Nullable O owner = event.castOwner(possibleOwner); -+ if (owner != null) { -+ event.setOwner(owner); -+ } else { -+ throw new IllegalStateException("Found invalid owner " + possibleOwner + " for event " + event); -+ } -+ } -+ -+ public void unregisterAllEventHandlersFor(final Plugin plugin) { -+ for (final LifecycleEventType lifecycleEventType : this.lifecycleEventTypes) { -+ this.removeEventHandlersOwnedBy(lifecycleEventType, plugin); -+ } -+ } -+ -+ private void removeEventHandlersOwnedBy(final LifecycleEventType eventType, final Plugin possibleOwner) { -+ final AbstractLifecycleEventType lifecycleEventType = (AbstractLifecycleEventType) eventType; -+ lifecycleEventType.removeMatching(registeredHandler -> registeredHandler.owner().getPluginMeta().getName().equals(possibleOwner.getPluginMeta().getName())); -+ } -+ -+ @SuppressWarnings("unchecked") -+ public > void callStaticRegistrarEvent(final LifecycleEventType, ?> lifecycleEventType, final R registrar, final Class ownerClass) { -+ this.callEvent((LifecycleEventType, ?>) lifecycleEventType, new RegistrarEventImpl<>(registrar, ownerClass), ownerClass::isInstance); -+ } -+ -+ @SuppressWarnings("unchecked") -+ public > void callReloadableRegistrarEvent(final LifecycleEventType, ?> lifecycleEventType, final R registrar, final Class ownerClass, final ReloadableRegistrarEvent.Cause cause) { -+ this.callEvent((LifecycleEventType, ?>) lifecycleEventType, new RegistrarEventImpl.ReloadableImpl<>(registrar, ownerClass, cause), ownerClass::isInstance); -+ } -+ -+ private LifecycleEventRunner() { -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e941405269a773e8a77e26ffd1afd84f53fadff5 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java -@@ -0,0 +1,10 @@ -+package io.papermc.paper.plugin.lifecycle.event; -+ -+public interface PaperLifecycleEvent extends LifecycleEvent { -+ -+ // called after all handlers have been run. Can be -+ // used to invalid various contexts to plugins can't -+ // try to re-use them by storing them from the event -+ default void invalidate() { -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d05334016bd01201c755dea04c0cea56b6dfcb50 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java -@@ -0,0 +1,26 @@ -+package io.papermc.paper.plugin.lifecycle.event; -+ -+import com.google.common.base.Preconditions; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; -+import java.util.function.BooleanSupplier; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public final class PaperLifecycleEventManager implements LifecycleEventManager { -+ -+ private final O owner; -+ public final BooleanSupplier registrationCheck; -+ -+ public PaperLifecycleEventManager(final O owner, final BooleanSupplier registrationCheck) { -+ this.owner = owner; -+ this.registrationCheck = registrationCheck; -+ } -+ -+ @Override -+ public void registerEventHandler(final LifecycleEventHandlerConfiguration handlerConfiguration) { -+ Preconditions.checkState(this.registrationCheck.getAsBoolean(), "Cannot register lifecycle event handlers"); -+ ((AbstractLifecycleEventHandlerConfiguration) handlerConfiguration).registerFrom(this.owner); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fa216e6fd804859293385ed43c53dfca057f317f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java -@@ -0,0 +1,28 @@ -+package io.papermc.paper.plugin.lifecycle.event.handler.configuration; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public abstract class AbstractLifecycleEventHandlerConfiguration implements LifecycleEventHandlerConfiguration { -+ -+ private final LifecycleEventHandler handler; -+ private final AbstractLifecycleEventType type; -+ -+ protected AbstractLifecycleEventHandlerConfiguration(final LifecycleEventHandler handler, final AbstractLifecycleEventType type) { -+ this.handler = handler; -+ this.type = type; -+ } -+ -+ public final void registerFrom(final O owner) { -+ this.type.tryRegister(owner, this); -+ } -+ -+ public LifecycleEventHandler handler() { -+ return this.handler; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ab444d60d72bd692843052df5d7b24fbb5621cf7 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java -@@ -0,0 +1,28 @@ -+package io.papermc.paper.plugin.lifecycle.event.handler.configuration; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public class MonitorLifecycleEventHandlerConfigurationImpl extends AbstractLifecycleEventHandlerConfiguration implements MonitorLifecycleEventHandlerConfiguration { -+ -+ private boolean monitor = false; -+ -+ public MonitorLifecycleEventHandlerConfigurationImpl(final LifecycleEventHandler handler, final AbstractLifecycleEventType eventType) { -+ super(handler, eventType); -+ } -+ -+ public boolean isMonitor() { -+ return this.monitor; -+ } -+ -+ @Override -+ public MonitorLifecycleEventHandlerConfiguration monitor() { -+ this.monitor = true; -+ return this; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ccdad31717bf12b844cbeaf11a49247485ec77f1 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java -@@ -0,0 +1,40 @@ -+package io.papermc.paper.plugin.lifecycle.event.handler.configuration; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; -+import java.util.OptionalInt; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public class PrioritizedLifecycleEventHandlerConfigurationImpl -+ extends AbstractLifecycleEventHandlerConfiguration -+ implements PrioritizedLifecycleEventHandlerConfiguration { -+ -+ private static final OptionalInt DEFAULT_PRIORITY = OptionalInt.of(0); -+ private static final OptionalInt MONITOR_PRIORITY = OptionalInt.empty(); -+ -+ private OptionalInt priority = DEFAULT_PRIORITY; -+ -+ public PrioritizedLifecycleEventHandlerConfigurationImpl(final LifecycleEventHandler handler, final AbstractLifecycleEventType eventType) { -+ super(handler, eventType); -+ } -+ -+ public OptionalInt priority() { -+ return this.priority; -+ } -+ -+ @Override -+ public PrioritizedLifecycleEventHandlerConfiguration priority(final int priority) { -+ this.priority = OptionalInt.of(priority); -+ return this; -+ } -+ -+ @Override -+ public PrioritizedLifecycleEventHandlerConfiguration monitor() { -+ this.priority = MONITOR_PRIORITY; -+ return this; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b2586c881988fbabe07eef1b43eb1b55f2d3fa52 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java -@@ -0,0 +1,15 @@ -+package io.papermc.paper.plugin.lifecycle.event.registrar; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public interface PaperRegistrar extends Registrar { -+ -+ void setCurrentContext(@Nullable O owner); -+ -+ default void invalidate() { -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6d530c52aaf0dc2cdfe3bd56af557274a7f44256 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java -@@ -0,0 +1,70 @@ -+package io.papermc.paper.plugin.lifecycle.event.registrar; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.types.OwnerAwareLifecycleEvent; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public class RegistrarEventImpl, O extends LifecycleEventOwner> implements PaperLifecycleEvent, OwnerAwareLifecycleEvent, RegistrarEvent { -+ -+ private final R registrar; -+ private final Class ownerClass; -+ -+ public RegistrarEventImpl(final R registrar, final Class ownerClass) { -+ this.registrar = registrar; -+ this.ownerClass = ownerClass; -+ } -+ -+ @Override -+ public R registrar() { -+ return this.registrar; -+ } -+ -+ @Override -+ public final void setOwner(final @Nullable O owner) { -+ this.registrar.setCurrentContext(owner); -+ } -+ -+ @Override -+ public final @Nullable O castOwner(final LifecycleEventOwner owner) { -+ return this.ownerClass.isInstance(owner) ? this.ownerClass.cast(owner) : null; -+ } -+ -+ @Override -+ public void invalidate() { -+ this.registrar.invalidate(); -+ } -+ -+ @Override -+ public String toString() { -+ return "RegistrarEventImpl{" + -+ "registrar=" + this.registrar + -+ ", ownerClass=" + this.ownerClass + -+ '}'; -+ } -+ -+ public static class ReloadableImpl, O extends LifecycleEventOwner> extends RegistrarEventImpl implements ReloadableRegistrarEvent { -+ -+ private final ReloadableRegistrarEvent.Cause cause; -+ -+ public ReloadableImpl(final R registrar, final Class ownerClass, final Cause cause) { -+ super(registrar, ownerClass); -+ this.cause = cause; -+ } -+ -+ @Override -+ public Cause cause() { -+ return this.cause; -+ } -+ -+ @Override -+ public String toString() { -+ return "ReloadableImpl{" + -+ "cause=" + this.cause + -+ "} " + super.toString(); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..01a4e9a36a9970f30ed9f9236fc5a4a1cf71844e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java -@@ -0,0 +1,62 @@ -+package io.papermc.paper.plugin.lifecycle.event.types; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; -+import java.util.function.Consumer; -+import java.util.function.Predicate; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public abstract class AbstractLifecycleEventType> implements LifecycleEventType { -+ -+ private final String name; -+ private final Class ownerType; -+ -+ protected AbstractLifecycleEventType(final String name, final Class ownerType) { -+ this.name = name; -+ this.ownerType = ownerType; -+ LifecycleEventRunner.INSTANCE.addEventType(this); -+ } -+ -+ @Override -+ public String name() { -+ return this.name; -+ } -+ -+ private void verifyOwner(final O owner) { -+ if (!this.ownerType.isInstance(owner)) { -+ throw new IllegalArgumentException("You cannot register the lifecycle event '" + this.name + "' on " + owner); -+ } -+ } -+ -+ public boolean blocksReloading(final O eventOwner) { -+ return eventOwner instanceof BootstrapContext; -+ } -+ -+ public abstract boolean hasHandlers(); -+ -+ public abstract void forEachHandler(E event, Consumer> consumer, Predicate> predicate); -+ -+ public abstract void removeMatching(Predicate> predicate); -+ -+ protected abstract void register(O owner, AbstractLifecycleEventHandlerConfiguration config); -+ -+ public final void tryRegister(final O owner, final AbstractLifecycleEventHandlerConfiguration config) { -+ this.verifyOwner(owner); -+ LifecycleEventRunner.INSTANCE.checkRegisteredHandler(owner, this); -+ this.register(owner, config); -+ } -+ -+ public record RegisteredHandler(O owner, AbstractLifecycleEventHandlerConfiguration config) { -+ -+ public LifecycleEventHandler lifecycleEventHandler() { -+ return this.config().handler(); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b11346e04bb16c3238f32deb87dbd680e261d4d2 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java -@@ -0,0 +1,25 @@ -+package io.papermc.paper.plugin.lifecycle.event.types; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public final class LifecycleEventTypeProviderImpl implements LifecycleEventTypeProvider { -+ -+ public static LifecycleEventTypeProviderImpl instance() { -+ return (LifecycleEventTypeProviderImpl) LifecycleEventTypeProvider.provider(); -+ } -+ -+ @Override -+ public LifecycleEventType.Monitorable monitor(final String name, final Class ownerType) { -+ return new MonitorableLifecycleEventType<>(name, ownerType); -+ } -+ -+ @Override -+ public LifecycleEventType.Prioritizable prioritized(final String name, final Class ownerType) { -+ return new PrioritizableLifecycleEventType.Simple<>(name, ownerType); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..abb969cf6ed967fe7720c56d3b3157bd1b74700d ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java -@@ -0,0 +1,63 @@ -+package io.papermc.paper.plugin.lifecycle.event.types; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.MonitorLifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.MonitorLifecycleEventHandlerConfigurationImpl; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.function.Consumer; -+import java.util.function.Predicate; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public class MonitorableLifecycleEventType extends AbstractLifecycleEventType> implements LifecycleEventType.Monitorable { -+ -+ final List> handlers = new ArrayList<>(); -+ int nonMonitorIdx = 0; -+ -+ public MonitorableLifecycleEventType(final String name, final Class ownerType) { -+ super(name, ownerType); -+ } -+ -+ @Override -+ public boolean hasHandlers() { -+ return !this.handlers.isEmpty(); -+ } -+ -+ @Override -+ public MonitorLifecycleEventHandlerConfigurationImpl newHandler(final LifecycleEventHandler handler) { -+ return new MonitorLifecycleEventHandlerConfigurationImpl<>(handler, this); -+ } -+ -+ @Override -+ protected void register(final O owner, final AbstractLifecycleEventHandlerConfiguration config) { -+ if (!(config instanceof final MonitorLifecycleEventHandlerConfigurationImpl monitor)) { -+ throw new IllegalArgumentException("Configuration must be a MonitorLifecycleEventHandlerConfiguration"); -+ } -+ final RegisteredHandler registeredHandler = new RegisteredHandler<>(owner, config); -+ if (!monitor.isMonitor()) { -+ this.handlers.add(this.nonMonitorIdx, registeredHandler); -+ this.nonMonitorIdx++; -+ } else { -+ this.handlers.add(registeredHandler); -+ } -+ } -+ -+ @Override -+ public void forEachHandler(final E event, final Consumer> consumer, final Predicate> predicate) { -+ for (final RegisteredHandler handler : this.handlers) { -+ if (predicate.test(handler)) { -+ consumer.accept(handler); -+ } -+ } -+ } -+ -+ @Override -+ public void removeMatching(final Predicate> predicate) { -+ this.handlers.removeIf(predicate); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3e7e7474f301c0725fa2bcd6e19e476fc35f2d5a ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java -@@ -0,0 +1,15 @@ -+package io.papermc.paper.plugin.lifecycle.event.types; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public interface OwnerAwareLifecycleEvent extends LifecycleEvent { -+ -+ void setOwner(@Nullable O owner); -+ -+ @Nullable O castOwner(LifecycleEventOwner owner); -+} -diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2ed622a61ddc37b11888867770b513909b9a2ecc ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java -@@ -0,0 +1,79 @@ -+package io.papermc.paper.plugin.lifecycle.event.types; -+ -+import com.google.common.base.Preconditions; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfigurationImpl; -+import java.util.ArrayList; -+import java.util.Comparator; -+import java.util.List; -+import java.util.function.Consumer; -+import java.util.function.Predicate; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+@DefaultQualifier(NonNull.class) -+public abstract class PrioritizableLifecycleEventType< -+ O extends LifecycleEventOwner, -+ E extends LifecycleEvent, -+ C extends PrioritizedLifecycleEventHandlerConfiguration -+> extends AbstractLifecycleEventType { -+ -+ private static final Comparator> COMPARATOR = Comparator.comparing(handler -> ((PrioritizedLifecycleEventHandlerConfigurationImpl) handler.config()).priority(), (o1, o2) -> { -+ if (o1.equals(o2)) { -+ return 0; -+ } else if (o1.isEmpty()) { -+ return 1; -+ } else if (o2.isEmpty()) { -+ return -1; -+ } else { -+ return Integer.compare(o1.getAsInt(), o2.getAsInt()); -+ } -+ }); -+ -+ private final List> handlers = new ArrayList<>(); -+ -+ public PrioritizableLifecycleEventType(final String name, final Class ownerType) { -+ super(name, ownerType); -+ } -+ -+ @Override -+ public boolean hasHandlers() { -+ return !this.handlers.isEmpty(); -+ } -+ -+ @Override -+ protected void register(final O owner, final AbstractLifecycleEventHandlerConfiguration config) { -+ Preconditions.checkArgument(config instanceof PrioritizedLifecycleEventHandlerConfigurationImpl, "Configuration must be a PrioritizedLifecycleEventHandlerConfiguration"); -+ this.handlers.add(new RegisteredHandler<>(owner, config)); -+ this.handlers.sort(COMPARATOR); -+ } -+ -+ @Override -+ public void forEachHandler(final E event, final Consumer> consumer, final Predicate> predicate) { -+ for (final RegisteredHandler handler : this.handlers) { -+ if (predicate.test(handler)) { -+ consumer.accept(handler); -+ } -+ } -+ } -+ -+ @Override -+ public void removeMatching(final Predicate> predicate) { -+ this.handlers.removeIf(predicate); -+ } -+ -+ public static class Simple extends PrioritizableLifecycleEventType> implements LifecycleEventType.Prioritizable { -+ public Simple(final String name, final Class ownerType) { -+ super(name, ownerType); -+ } -+ -+ @Override -+ public PrioritizedLifecycleEventHandlerConfiguration newHandler(final LifecycleEventHandler handler) { -+ return new PrioritizedLifecycleEventHandlerConfigurationImpl<>(handler, this); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -index 834b85f24df023642f8abf7213fe578ac8c17a3e..3e82ea07ca4194844c5528446e2c4a46ff4acee5 100644 ---- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -@@ -293,6 +293,15 @@ class PaperPluginInstanceManager { - + pluginName + " (Is it up to date?)", ex, plugin); // Paper - } - -+ // Paper start - lifecycle event system -+ try { -+ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.unregisterAllEventHandlersFor(plugin); -+ } catch (Throwable ex) { -+ this.handlePluginException("Error occurred (in the plugin loader) while unregistering lifecycle event handlers for " -+ + pluginName + " (Is it up to date?)", ex, plugin); -+ } -+ // Paper end -+ - try { - this.server.getMessenger().unregisterIncomingPluginChannel(plugin); - this.server.getMessenger().unregisterOutgoingPluginChannel(plugin); -diff --git a/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java b/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java -index 2e96308696e131f3f013469a395e5ddda2c5d529..65a66e484c1c39c5f41d97db52f31c67b4479d20 100644 ---- a/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java -+++ b/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java -@@ -32,8 +32,9 @@ public class BootstrapProviderStorage extends SimpleProviderStorage provider, PluginBootstrap provided) { - try { -- BootstrapContext context = PluginBootstrapContextImpl.create(provider, PluginInitializerManager.instance().pluginDirectoryPath()); -+ PluginBootstrapContextImpl context = PluginBootstrapContextImpl.create(provider, PluginInitializerManager.instance().pluginDirectoryPath()); // Paper - lifecycle events - provided.bootstrap(context); -+ context.lockLifecycleEventRegistration(); // Paper - lifecycle events - return true; - } catch (Throwable e) { - LOGGER.error("Failed to run bootstrapper for %s. This plugin will not be loaded.".formatted(provider.getSource()), e); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 83c3de4ae733199f64fe0f967f9f816545d20f1c..581a15957478fd9f394a27269c2bd68a117ad8c2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1051,6 +1051,11 @@ public final class CraftServer implements Server { - - @Override - public void reload() { -+ // Paper start - lifecycle events -+ if (io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.blocksPluginReloading()) { -+ throw new IllegalStateException("A lifecycle event handler has been registered which makes reloading plugins not possible"); -+ } -+ // Paper end - lifecycle events - org.spigotmc.WatchdogThread.hasStarted = false; // Paper - Disable watchdog early timeout on reload - this.reloadCount++; - this.configuration = YamlConfiguration.loadConfiguration(this.getConfigFile()); -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 7ae4567bc6f2f0374d1a4a3859f6329eaace7415..ca201861b383bac4ea93284ac017e85ae0b3b17c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -652,6 +652,13 @@ public final class CraftMagicNumbers implements UnsafeValues { - } - // Paper end - spawn egg color visibility - -+ // Paper start - lifecycle event API -+ @Override -+ public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck) { -+ return new io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEventManager<>(plugin, registrationCheck); -+ } -+ // Paper end - lifecycle event API -+ - /** - * This helper class represents the different NBT Tags. - *

-diff --git a/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider -new file mode 100644 -index 0000000000000000000000000000000000000000..808b1192b60348ad05f0bfbdeda6f94df4876743 ---- /dev/null -+++ b/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider -@@ -0,0 +1 @@ -+io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProviderImpl -diff --git a/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java b/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java -index 1d14f530ef888102e47eeeaf0d1a6076e51871c4..90cf0c702ca2ff9de64d9718ecba5f2d128953a6 100644 ---- a/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java -+++ b/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java -@@ -143,4 +143,11 @@ public class PaperTestPlugin extends PluginBase { - public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { - throw new UnsupportedOperationException("Not supported."); - } -+ -+ // Paper start - lifecycle events -+ @Override -+ public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager getLifecycleManager() { -+ throw new UnsupportedOperationException("Not supported."); -+ } -+ // Paper end - lifecycle events - } diff --git a/patches/server/0919-ItemStack-Tooltip-API.patch b/patches/server/0919-ItemStack-Tooltip-API.patch new file mode 100644 index 0000000000..f06c4356cd --- /dev/null +++ b/patches/server/0919-ItemStack-Tooltip-API.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yannick Lamprecht +Date: Mon, 22 Jan 2024 13:27:30 +0100 +Subject: [PATCH] ItemStack Tooltip API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 06d66c8043daec3c736d82d972ceb98d55eae9d1..51d5629b00ec4929c12ed9e6ba5a37f5903cf13e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -627,6 +627,19 @@ public final class CraftMagicNumbers implements UnsafeValues { + if (statistic.getType() != org.bukkit.Statistic.Type.UNTYPED) return "minecraft.custom:minecraft." + statistic.getKey().getKey(); + return org.bukkit.craftbukkit.CraftStatistic.getNMSStatistic(statistic).getName(); + } ++ ++ @Override ++ public java.util.List computeTooltipLines(final ItemStack itemStack, final io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, final org.bukkit.entity.Player player) { ++ Preconditions.checkArgument(tooltipContext != null, "tooltipContext cannot be null"); ++ net.minecraft.world.item.TooltipFlag.Default flag = tooltipContext.isAdvanced() ? net.minecraft.world.item.TooltipFlag.ADVANCED : net.minecraft.world.item.TooltipFlag.NORMAL; ++ if (tooltipContext.isCreative()) { ++ flag = flag.asCreative(); ++ } ++ final java.util.List lines = CraftItemStack.asNMSCopy(itemStack).getTooltipLines( ++ net.minecraft.world.item.Item.TooltipContext.of(player == null ? net.minecraft.server.MinecraftServer.getServer().registryAccess() : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle().level().registryAccess()), ++ player == null ? null : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle(), flag); ++ return lines.stream().map(io.papermc.paper.adventure.PaperAdventure::asAdventure).toList(); ++ } + // Paper end + + // Paper start - spawn egg color visibility diff --git a/patches/server/0920-Add-getChunkSnapshot-includeLightData-parameter.patch b/patches/server/0920-Add-getChunkSnapshot-includeLightData-parameter.patch new file mode 100644 index 0000000000..ba33560bab --- /dev/null +++ b/patches/server/0920-Add-getChunkSnapshot-includeLightData-parameter.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Sat, 10 Feb 2024 10:03:48 +0100 +Subject: [PATCH] Add getChunkSnapshot includeLightData parameter + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +index 887a17a0833064eb5701222e5fb6f5ccf9511588..5fc9e8e969debb3e15ed474b36a1c48b086d0449 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +@@ -328,12 +328,21 @@ public class CraftChunk implements Chunk { + + @Override + public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain) { ++ // Paper start - Add getChunkSnapshot includeLightData parameter ++ return getChunkSnapshot(includeMaxBlockY, includeBiome, includeBiomeTempRain, true); ++ } ++ ++ @Override ++ public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain, boolean includeLightData) { ++ // Paper end - Add getChunkSnapshot includeLightData parameter + ChunkAccess chunk = this.getHandle(ChunkStatus.FULL); + + LevelChunkSection[] cs = chunk.getSections(); + PalettedContainer[] sectionBlockIDs = new PalettedContainer[cs.length]; +- byte[][] sectionSkyLights = new byte[cs.length][]; +- byte[][] sectionEmitLights = new byte[cs.length][]; ++ // Paper start - Add getChunkSnapshot includeLightData parameter ++ byte[][] sectionSkyLights = includeLightData ? new byte[cs.length][] : null; ++ byte[][] sectionEmitLights = includeLightData ? new byte[cs.length][] : null; ++ // Paper end - Add getChunkSnapshot includeLightData parameter + boolean[] sectionEmpty = new boolean[cs.length]; + PalettedContainerRO>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null; + +@@ -350,6 +359,7 @@ public class CraftChunk implements Chunk { + } + // Paper end - Fix ChunkSnapshot#isSectionEmpty(int) + ++ if (includeLightData) { // Paper - Add getChunkSnapshot includeLightData parameter + LevelLightEngine lightengine = this.worldServer.getLightEngine(); + DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index + if (skyLightArray == null) { +@@ -365,6 +375,7 @@ public class CraftChunk implements Chunk { + sectionEmitLights[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, sectionEmitLights[i], 0, 2048); + } ++ } // Paper - Add getChunkSnapshot includeLightData parameter + + if (biome != null) { + biome[i] = ((PalettedContainer>) cs[i].getBiomes()).copy(); // Paper - Perf: use copy instead of round tripping with codecs +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java +index c88e4ba701b2a2325b76478b7f47278157afd2ef..ddcbdbcbfeb6efe0a587b1181505423cc9d2c951 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java +@@ -119,6 +119,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot { + + @Override + public final int getBlockSkyLight(int x, int y, int z) { ++ Preconditions.checkState(this.skylight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter + this.validateChunkCoordinates(x, y, z); + + int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); +@@ -127,6 +128,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot { + + @Override + public final int getBlockEmittedLight(int x, int y, int z) { ++ Preconditions.checkState(this.emitlight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter + this.validateChunkCoordinates(x, y, z); + + int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); diff --git a/patches/server/0920-ItemStack-Tooltip-API.patch b/patches/server/0920-ItemStack-Tooltip-API.patch deleted file mode 100644 index 7279f30261..0000000000 --- a/patches/server/0920-ItemStack-Tooltip-API.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Yannick Lamprecht -Date: Mon, 22 Jan 2024 13:27:30 +0100 -Subject: [PATCH] ItemStack Tooltip API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index ca201861b383bac4ea93284ac017e85ae0b3b17c..8feba2bd411abe36e64a39a0c599c73d07c19e20 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -628,6 +628,21 @@ public final class CraftMagicNumbers implements UnsafeValues { - } - // Paper end - fix custom stats criteria creation - -+ // Paper start - expose itemstack tooltip lines -+ @Override -+ public java.util.List computeTooltipLines(final ItemStack itemStack, final io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, final org.bukkit.entity.Player player) { -+ Preconditions.checkArgument(tooltipContext != null, "tooltipContext cannot be null"); -+ net.minecraft.world.item.TooltipFlag.Default flag = tooltipContext.isAdvanced() ? net.minecraft.world.item.TooltipFlag.ADVANCED : net.minecraft.world.item.TooltipFlag.NORMAL; -+ if (tooltipContext.isCreative()) { -+ flag = flag.asCreative(); -+ } -+ final java.util.List lines = CraftItemStack.asNMSCopy(itemStack).getTooltipLines( -+ net.minecraft.world.item.Item.TooltipContext.of(player == null ? net.minecraft.server.MinecraftServer.getServer().registryAccess() : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle().level().registryAccess()), -+ player == null ? null : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle(), flag); -+ return lines.stream().map(io.papermc.paper.adventure.PaperAdventure::asAdventure).toList(); -+ } -+ // Paper end - expose itemstack tooltip lines -+ - @Override - public String get(Class aClass, String s) { - if (aClass == Enchantment.class) { diff --git a/patches/server/0921-Add-FluidState-API.patch b/patches/server/0921-Add-FluidState-API.patch new file mode 100644 index 0000000000..e1e2fe004f --- /dev/null +++ b/patches/server/0921-Add-FluidState-API.patch @@ -0,0 +1,208 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: vicisacat +Date: Fri, 17 Nov 2023 20:22:43 +0100 +Subject: [PATCH] Add FluidState API + + +diff --git a/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..479bc32241ebadf8bbc1080b601f61391ad37fa4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java +@@ -0,0 +1,110 @@ ++package io.papermc.paper.block.fluid; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.block.fluid.type.PaperFallingFluidData; ++import io.papermc.paper.block.fluid.type.PaperFlowingFluidData; ++import io.papermc.paper.util.MCUtil; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.function.Function; ++import net.minecraft.world.level.material.FluidState; ++import net.minecraft.world.level.material.LavaFluid; ++import net.minecraft.world.level.material.WaterFluid; ++import org.bukkit.Fluid; ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.CraftFluid; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.util.CraftVector; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.NotNull; ++ ++public class PaperFluidData implements FluidData { ++ ++ private final FluidState state; ++ ++ protected PaperFluidData(final FluidState state) { ++ this.state = state; ++ } ++ ++ /** ++ * Provides the internal server representation of this fluid data. ++ * @return the fluid state. ++ */ ++ public FluidState getState() { ++ return this.state; ++ } ++ ++ @Override ++ public final @NotNull Fluid getFluidType() { ++ return CraftFluid.minecraftToBukkit(this.state.getType()); ++ } ++ ++ @Override ++ public @NotNull PaperFluidData clone() { ++ try { ++ return (PaperFluidData) super.clone(); ++ } catch (final CloneNotSupportedException ex) { ++ throw new AssertionError("Clone not supported", ex); ++ } ++ } ++ ++ @Override ++ public @NotNull Vector computeFlowDirection(final Location location) { ++ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute flow direction on world-less location"); ++ return CraftVector.toBukkit(this.state.getFlow( ++ ((CraftWorld) location.getWorld()).getHandle(), ++ MCUtil.toBlockPosition(location) ++ )); ++ } ++ ++ @Override ++ public int getLevel() { ++ return this.state.getAmount(); ++ } ++ ++ @Override ++ public float computeHeight(@NotNull final Location location) { ++ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute height on world-less location"); ++ return this.state.getHeight(((CraftWorld) location.getWorld()).getHandle(), MCUtil.toBlockPos(location)); ++ } ++ ++ @Override ++ public boolean isSource() { ++ return this.state.isSource(); ++ } ++ ++ @Override ++ public int hashCode() { ++ return this.state.hashCode(); ++ } ++ ++ @Override ++ public boolean equals(final Object obj) { ++ return obj instanceof final PaperFluidData paperFluidData && this.state.equals(paperFluidData.state); ++ } ++ ++ @Override ++ public String toString() { ++ return "PaperFluidData{" + this.state + "}"; ++ } ++ ++ /* Registry */ ++ private static final Map, Function> MAP = new HashMap<>(); ++ static { ++ // ++ register(LavaFluid.Source.class, PaperFallingFluidData::new); ++ register(WaterFluid.Source.class, PaperFallingFluidData::new); ++ register(LavaFluid.Flowing.class, PaperFlowingFluidData::new); ++ register(WaterFluid.Flowing.class, PaperFlowingFluidData::new); ++ // ++ } ++ ++ static void register(final Class fluid, final Function creator) { ++ Preconditions.checkState(MAP.put(fluid, creator) == null, "Duplicate mapping %s->%s", fluid, creator); ++ MAP.put(fluid, creator); ++ } ++ ++ public static PaperFluidData createData(final FluidState state) { ++ return MAP.getOrDefault(state.getType().getClass(), PaperFluidData::new).apply(state); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/block/fluid/package-info.java b/src/main/java/io/papermc/paper/block/fluid/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cfabb814ebd281aab299c6c655266ff357e08806 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/fluid/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.block.fluid; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..655dbd83ff4e632f1168b75e9b402b05aa9d8edf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java +@@ -0,0 +1,18 @@ ++ ++package io.papermc.paper.block.fluid.type; ++ ++import io.papermc.paper.block.fluid.PaperFluidData; ++import net.minecraft.world.level.material.FlowingFluid; ++import net.minecraft.world.level.material.FluidState; ++ ++public class PaperFallingFluidData extends PaperFluidData implements FallingFluidData { ++ ++ public PaperFallingFluidData(final FluidState state) { ++ super(state); ++ } ++ ++ @Override ++ public boolean isFalling() { ++ return this.getState().getValue(FlowingFluid.FALLING); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c0c2805cb045cdd835b402776a6923fe2ecc2a99 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java +@@ -0,0 +1,11 @@ ++package io.papermc.paper.block.fluid.type; ++ ++import net.minecraft.world.level.material.FluidState; ++ ++public class PaperFlowingFluidData extends PaperFallingFluidData implements FlowingFluidData { ++ ++ public PaperFlowingFluidData(final FluidState state) { ++ super(state); ++ } ++ ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +index 4c234e887c42b27754ed8f05f2000d9309274427..f0bd7d01f56bb792886354ca4f199e46c2cf7503 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +@@ -108,6 +108,13 @@ public abstract class CraftRegionAccessor implements RegionAccessor { + return CraftBlock.at(this.getHandle(), new BlockPos(x, y, z)).getState(); + } + ++ // Paper start - FluidState API ++ @Override ++ public io.papermc.paper.block.fluid.FluidData getFluidData(final int x, final int y, final int z) { ++ return io.papermc.paper.block.fluid.PaperFluidData.createData(getHandle().getFluidState(new BlockPos(x, y, z))); ++ } ++ // Paper end ++ + @Override + public BlockData getBlockData(Location location) { + return this.getBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ()); +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +index a23269e3bdb83f85a1d08d5f7b54742025223ada..a57ac9dc8d08b12ec00ad41d9a1779e5a81e4e8b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +@@ -304,4 +304,11 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe + return centerChunkZ; + } + // Paper end - Add more LimitedRegion API ++ // Paper start - Fluid API ++ @Override ++ public io.papermc.paper.block.fluid.FluidData getFluidData(int x, int y, int z) { ++ Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); ++ return super.getFluidData(x, y, z); ++ } ++ // Paper end + } diff --git a/patches/server/0921-Add-getChunkSnapshot-includeLightData-parameter.patch b/patches/server/0921-Add-getChunkSnapshot-includeLightData-parameter.patch deleted file mode 100644 index ba33560bab..0000000000 --- a/patches/server/0921-Add-getChunkSnapshot-includeLightData-parameter.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Sat, 10 Feb 2024 10:03:48 +0100 -Subject: [PATCH] Add getChunkSnapshot includeLightData parameter - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -index 887a17a0833064eb5701222e5fb6f5ccf9511588..5fc9e8e969debb3e15ed474b36a1c48b086d0449 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -@@ -328,12 +328,21 @@ public class CraftChunk implements Chunk { - - @Override - public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain) { -+ // Paper start - Add getChunkSnapshot includeLightData parameter -+ return getChunkSnapshot(includeMaxBlockY, includeBiome, includeBiomeTempRain, true); -+ } -+ -+ @Override -+ public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain, boolean includeLightData) { -+ // Paper end - Add getChunkSnapshot includeLightData parameter - ChunkAccess chunk = this.getHandle(ChunkStatus.FULL); - - LevelChunkSection[] cs = chunk.getSections(); - PalettedContainer[] sectionBlockIDs = new PalettedContainer[cs.length]; -- byte[][] sectionSkyLights = new byte[cs.length][]; -- byte[][] sectionEmitLights = new byte[cs.length][]; -+ // Paper start - Add getChunkSnapshot includeLightData parameter -+ byte[][] sectionSkyLights = includeLightData ? new byte[cs.length][] : null; -+ byte[][] sectionEmitLights = includeLightData ? new byte[cs.length][] : null; -+ // Paper end - Add getChunkSnapshot includeLightData parameter - boolean[] sectionEmpty = new boolean[cs.length]; - PalettedContainerRO>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null; - -@@ -350,6 +359,7 @@ public class CraftChunk implements Chunk { - } - // Paper end - Fix ChunkSnapshot#isSectionEmpty(int) - -+ if (includeLightData) { // Paper - Add getChunkSnapshot includeLightData parameter - LevelLightEngine lightengine = this.worldServer.getLightEngine(); - DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index - if (skyLightArray == null) { -@@ -365,6 +375,7 @@ public class CraftChunk implements Chunk { - sectionEmitLights[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, sectionEmitLights[i], 0, 2048); - } -+ } // Paper - Add getChunkSnapshot includeLightData parameter - - if (biome != null) { - biome[i] = ((PalettedContainer>) cs[i].getBiomes()).copy(); // Paper - Perf: use copy instead of round tripping with codecs -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java -index c88e4ba701b2a2325b76478b7f47278157afd2ef..ddcbdbcbfeb6efe0a587b1181505423cc9d2c951 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java -@@ -119,6 +119,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot { - - @Override - public final int getBlockSkyLight(int x, int y, int z) { -+ Preconditions.checkState(this.skylight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter - this.validateChunkCoordinates(x, y, z); - - int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); -@@ -127,6 +128,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot { - - @Override - public final int getBlockEmittedLight(int x, int y, int z) { -+ Preconditions.checkState(this.emitlight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter - this.validateChunkCoordinates(x, y, z); - - int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); diff --git a/patches/server/0922-Add-FluidState-API.patch b/patches/server/0922-Add-FluidState-API.patch deleted file mode 100644 index e1e2fe004f..0000000000 --- a/patches/server/0922-Add-FluidState-API.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: vicisacat -Date: Fri, 17 Nov 2023 20:22:43 +0100 -Subject: [PATCH] Add FluidState API - - -diff --git a/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java -new file mode 100644 -index 0000000000000000000000000000000000000000..479bc32241ebadf8bbc1080b601f61391ad37fa4 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java -@@ -0,0 +1,110 @@ -+package io.papermc.paper.block.fluid; -+ -+import com.google.common.base.Preconditions; -+import io.papermc.paper.block.fluid.type.PaperFallingFluidData; -+import io.papermc.paper.block.fluid.type.PaperFlowingFluidData; -+import io.papermc.paper.util.MCUtil; -+import java.util.HashMap; -+import java.util.Map; -+import java.util.function.Function; -+import net.minecraft.world.level.material.FluidState; -+import net.minecraft.world.level.material.LavaFluid; -+import net.minecraft.world.level.material.WaterFluid; -+import org.bukkit.Fluid; -+import org.bukkit.Location; -+import org.bukkit.craftbukkit.CraftFluid; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.craftbukkit.util.CraftVector; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.NotNull; -+ -+public class PaperFluidData implements FluidData { -+ -+ private final FluidState state; -+ -+ protected PaperFluidData(final FluidState state) { -+ this.state = state; -+ } -+ -+ /** -+ * Provides the internal server representation of this fluid data. -+ * @return the fluid state. -+ */ -+ public FluidState getState() { -+ return this.state; -+ } -+ -+ @Override -+ public final @NotNull Fluid getFluidType() { -+ return CraftFluid.minecraftToBukkit(this.state.getType()); -+ } -+ -+ @Override -+ public @NotNull PaperFluidData clone() { -+ try { -+ return (PaperFluidData) super.clone(); -+ } catch (final CloneNotSupportedException ex) { -+ throw new AssertionError("Clone not supported", ex); -+ } -+ } -+ -+ @Override -+ public @NotNull Vector computeFlowDirection(final Location location) { -+ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute flow direction on world-less location"); -+ return CraftVector.toBukkit(this.state.getFlow( -+ ((CraftWorld) location.getWorld()).getHandle(), -+ MCUtil.toBlockPosition(location) -+ )); -+ } -+ -+ @Override -+ public int getLevel() { -+ return this.state.getAmount(); -+ } -+ -+ @Override -+ public float computeHeight(@NotNull final Location location) { -+ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute height on world-less location"); -+ return this.state.getHeight(((CraftWorld) location.getWorld()).getHandle(), MCUtil.toBlockPos(location)); -+ } -+ -+ @Override -+ public boolean isSource() { -+ return this.state.isSource(); -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.state.hashCode(); -+ } -+ -+ @Override -+ public boolean equals(final Object obj) { -+ return obj instanceof final PaperFluidData paperFluidData && this.state.equals(paperFluidData.state); -+ } -+ -+ @Override -+ public String toString() { -+ return "PaperFluidData{" + this.state + "}"; -+ } -+ -+ /* Registry */ -+ private static final Map, Function> MAP = new HashMap<>(); -+ static { -+ // -+ register(LavaFluid.Source.class, PaperFallingFluidData::new); -+ register(WaterFluid.Source.class, PaperFallingFluidData::new); -+ register(LavaFluid.Flowing.class, PaperFlowingFluidData::new); -+ register(WaterFluid.Flowing.class, PaperFlowingFluidData::new); -+ // -+ } -+ -+ static void register(final Class fluid, final Function creator) { -+ Preconditions.checkState(MAP.put(fluid, creator) == null, "Duplicate mapping %s->%s", fluid, creator); -+ MAP.put(fluid, creator); -+ } -+ -+ public static PaperFluidData createData(final FluidState state) { -+ return MAP.getOrDefault(state.getType().getClass(), PaperFluidData::new).apply(state); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/block/fluid/package-info.java b/src/main/java/io/papermc/paper/block/fluid/package-info.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cfabb814ebd281aab299c6c655266ff357e08806 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/block/fluid/package-info.java -@@ -0,0 +1,5 @@ -+@DefaultQualifier(NonNull.class) -+package io.papermc.paper.block.fluid; -+ -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java -new file mode 100644 -index 0000000000000000000000000000000000000000..655dbd83ff4e632f1168b75e9b402b05aa9d8edf ---- /dev/null -+++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java -@@ -0,0 +1,18 @@ -+ -+package io.papermc.paper.block.fluid.type; -+ -+import io.papermc.paper.block.fluid.PaperFluidData; -+import net.minecraft.world.level.material.FlowingFluid; -+import net.minecraft.world.level.material.FluidState; -+ -+public class PaperFallingFluidData extends PaperFluidData implements FallingFluidData { -+ -+ public PaperFallingFluidData(final FluidState state) { -+ super(state); -+ } -+ -+ @Override -+ public boolean isFalling() { -+ return this.getState().getValue(FlowingFluid.FALLING); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c0c2805cb045cdd835b402776a6923fe2ecc2a99 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java -@@ -0,0 +1,11 @@ -+package io.papermc.paper.block.fluid.type; -+ -+import net.minecraft.world.level.material.FluidState; -+ -+public class PaperFlowingFluidData extends PaperFallingFluidData implements FlowingFluidData { -+ -+ public PaperFlowingFluidData(final FluidState state) { -+ super(state); -+ } -+ -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -index 4c234e887c42b27754ed8f05f2000d9309274427..f0bd7d01f56bb792886354ca4f199e46c2cf7503 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -@@ -108,6 +108,13 @@ public abstract class CraftRegionAccessor implements RegionAccessor { - return CraftBlock.at(this.getHandle(), new BlockPos(x, y, z)).getState(); - } - -+ // Paper start - FluidState API -+ @Override -+ public io.papermc.paper.block.fluid.FluidData getFluidData(final int x, final int y, final int z) { -+ return io.papermc.paper.block.fluid.PaperFluidData.createData(getHandle().getFluidState(new BlockPos(x, y, z))); -+ } -+ // Paper end -+ - @Override - public BlockData getBlockData(Location location) { - return this.getBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ()); -diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -index a23269e3bdb83f85a1d08d5f7b54742025223ada..a57ac9dc8d08b12ec00ad41d9a1779e5a81e4e8b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -@@ -304,4 +304,11 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe - return centerChunkZ; - } - // Paper end - Add more LimitedRegion API -+ // Paper start - Fluid API -+ @Override -+ public io.papermc.paper.block.fluid.FluidData getFluidData(int x, int y, int z) { -+ Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); -+ return super.getFluidData(x, y, z); -+ } -+ // Paper end - } diff --git a/patches/server/0922-add-number-format-api.patch b/patches/server/0922-add-number-format-api.patch new file mode 100644 index 0000000000..d412b5f929 --- /dev/null +++ b/patches/server/0922-add-number-format-api.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Mayr +Date: Sat, 16 Dec 2023 10:40:29 +0100 +Subject: [PATCH] add number format api + +== AT == +public net.minecraft.network.chat.numbers.FixedFormat value +public net.minecraft.network.chat.numbers.StyledFormat style + +diff --git a/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java b/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6064086cc76ef0df999c7057121d0ac22bd4df65 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.util; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.scoreboard.numbers.NumberFormat; ++ ++public final class PaperScoreboardFormat { ++ ++ private PaperScoreboardFormat() { ++ } ++ ++ public static net.minecraft.network.chat.numbers.NumberFormat asVanilla(final NumberFormat format) { ++ final net.minecraft.network.chat.numbers.NumberFormat vanilla; ++ if (format instanceof final io.papermc.paper.scoreboard.numbers.StyledFormat styled) { ++ vanilla = new net.minecraft.network.chat.numbers.StyledFormat(PaperAdventure.asVanilla(styled.style())); ++ } else if (format instanceof final io.papermc.paper.scoreboard.numbers.FixedFormat fixed) { ++ vanilla = new net.minecraft.network.chat.numbers.FixedFormat(io.papermc.paper.adventure.PaperAdventure ++ .asVanilla(fixed.component())); ++ } else if (format.equals(NumberFormat.blank())) { ++ vanilla = net.minecraft.network.chat.numbers.BlankFormat.INSTANCE; ++ } else { ++ throw new IllegalArgumentException("Unknown format type " + format.getClass()); ++ } ++ ++ return vanilla; ++ } ++ ++ public static NumberFormat asPaper(final net.minecraft.network.chat.numbers.NumberFormat vanilla) { ++ if (vanilla instanceof final net.minecraft.network.chat.numbers.StyledFormat styled) { ++ return NumberFormat.styled(PaperAdventure.asAdventure(styled.style)); ++ } else if (vanilla instanceof final net.minecraft.network.chat.numbers.FixedFormat fixed) { ++ return NumberFormat.fixed(io.papermc.paper.adventure.PaperAdventure.asAdventure(fixed.value)); ++ } else if (vanilla instanceof net.minecraft.network.chat.numbers.BlankFormat) { ++ return NumberFormat.blank(); ++ } ++ ++ throw new IllegalArgumentException("Unknown format type " + vanilla.getClass()); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +index 2d3abf2a1da487ead74d698cc5ea4eb729c35c8d..1fec80c4f02aab3770c05bac8bfa2b622625e630 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +@@ -153,6 +153,34 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective + } + // Paper end + ++ // Paper start - add number format ++ @Override ++ public io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat() { ++ this.checkState(); ++ ++ net.minecraft.network.chat.numbers.NumberFormat vanilla = this.objective.numberFormat(); ++ ++ if (vanilla == null) { ++ return null; ++ } ++ ++ return io.papermc.paper.util.PaperScoreboardFormat.asPaper(vanilla); ++ } ++ ++ ++ @Override ++ public void numberFormat(io.papermc.paper.scoreboard.numbers.NumberFormat format) { ++ this.checkState(); ++ ++ if (format == null) { ++ this.objective.setNumberFormat(null); ++ return; ++ } ++ ++ this.objective.setNumberFormat(io.papermc.paper.util.PaperScoreboardFormat.asVanilla(format)); ++ } ++ // Paper end - add number format ++ + @Override + public void unregister() { + CraftScoreboard scoreboard = this.checkState(); +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +index 74d9c407e971804bed420370f7b684d8658eb5aa..e307e897d6e1ba4cb21883dfeaf334bfbf56cfc4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +@@ -55,6 +55,41 @@ final class CraftScore implements Score { + this.objective.checkState().board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).set(score); + } + ++ ++ // Paper start - add number format ++ @Override ++ public io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat() { ++ ReadOnlyScoreInfo scoreInfo = this.objective.checkState().board ++ .getPlayerScoreInfo(this.entry, this.objective.getHandle()); ++ ++ if (scoreInfo == null) { ++ return null; ++ } ++ ++ net.minecraft.network.chat.numbers.NumberFormat vanilla = scoreInfo.numberFormat(); ++ ++ if (vanilla == null) { ++ return null; ++ } ++ ++ return io.papermc.paper.util.PaperScoreboardFormat.asPaper(vanilla); ++ } ++ ++ ++ @Override ++ public void numberFormat(io.papermc.paper.scoreboard.numbers.NumberFormat format) { ++ final net.minecraft.world.scores.ScoreAccess access = this.objective.checkState() ++ .board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()); ++ ++ if (format == null) { ++ access.numberFormatOverride(null); ++ return; ++ } ++ ++ access.numberFormatOverride(io.papermc.paper.util.PaperScoreboardFormat.asVanilla(format)); ++ } ++ // Paper end - add number format ++ + @Override + public boolean isScoreSet() { + Scoreboard board = this.objective.checkState().board; diff --git a/patches/server/0923-add-number-format-api.patch b/patches/server/0923-add-number-format-api.patch deleted file mode 100644 index d412b5f929..0000000000 --- a/patches/server/0923-add-number-format-api.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Mayr -Date: Sat, 16 Dec 2023 10:40:29 +0100 -Subject: [PATCH] add number format api - -== AT == -public net.minecraft.network.chat.numbers.FixedFormat value -public net.minecraft.network.chat.numbers.StyledFormat style - -diff --git a/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java b/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6064086cc76ef0df999c7057121d0ac22bd4df65 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java -@@ -0,0 +1,38 @@ -+package io.papermc.paper.util; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import io.papermc.paper.scoreboard.numbers.NumberFormat; -+ -+public final class PaperScoreboardFormat { -+ -+ private PaperScoreboardFormat() { -+ } -+ -+ public static net.minecraft.network.chat.numbers.NumberFormat asVanilla(final NumberFormat format) { -+ final net.minecraft.network.chat.numbers.NumberFormat vanilla; -+ if (format instanceof final io.papermc.paper.scoreboard.numbers.StyledFormat styled) { -+ vanilla = new net.minecraft.network.chat.numbers.StyledFormat(PaperAdventure.asVanilla(styled.style())); -+ } else if (format instanceof final io.papermc.paper.scoreboard.numbers.FixedFormat fixed) { -+ vanilla = new net.minecraft.network.chat.numbers.FixedFormat(io.papermc.paper.adventure.PaperAdventure -+ .asVanilla(fixed.component())); -+ } else if (format.equals(NumberFormat.blank())) { -+ vanilla = net.minecraft.network.chat.numbers.BlankFormat.INSTANCE; -+ } else { -+ throw new IllegalArgumentException("Unknown format type " + format.getClass()); -+ } -+ -+ return vanilla; -+ } -+ -+ public static NumberFormat asPaper(final net.minecraft.network.chat.numbers.NumberFormat vanilla) { -+ if (vanilla instanceof final net.minecraft.network.chat.numbers.StyledFormat styled) { -+ return NumberFormat.styled(PaperAdventure.asAdventure(styled.style)); -+ } else if (vanilla instanceof final net.minecraft.network.chat.numbers.FixedFormat fixed) { -+ return NumberFormat.fixed(io.papermc.paper.adventure.PaperAdventure.asAdventure(fixed.value)); -+ } else if (vanilla instanceof net.minecraft.network.chat.numbers.BlankFormat) { -+ return NumberFormat.blank(); -+ } -+ -+ throw new IllegalArgumentException("Unknown format type " + vanilla.getClass()); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -index 2d3abf2a1da487ead74d698cc5ea4eb729c35c8d..1fec80c4f02aab3770c05bac8bfa2b622625e630 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -@@ -153,6 +153,34 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective - } - // Paper end - -+ // Paper start - add number format -+ @Override -+ public io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat() { -+ this.checkState(); -+ -+ net.minecraft.network.chat.numbers.NumberFormat vanilla = this.objective.numberFormat(); -+ -+ if (vanilla == null) { -+ return null; -+ } -+ -+ return io.papermc.paper.util.PaperScoreboardFormat.asPaper(vanilla); -+ } -+ -+ -+ @Override -+ public void numberFormat(io.papermc.paper.scoreboard.numbers.NumberFormat format) { -+ this.checkState(); -+ -+ if (format == null) { -+ this.objective.setNumberFormat(null); -+ return; -+ } -+ -+ this.objective.setNumberFormat(io.papermc.paper.util.PaperScoreboardFormat.asVanilla(format)); -+ } -+ // Paper end - add number format -+ - @Override - public void unregister() { - CraftScoreboard scoreboard = this.checkState(); -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -index 74d9c407e971804bed420370f7b684d8658eb5aa..e307e897d6e1ba4cb21883dfeaf334bfbf56cfc4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -@@ -55,6 +55,41 @@ final class CraftScore implements Score { - this.objective.checkState().board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).set(score); - } - -+ -+ // Paper start - add number format -+ @Override -+ public io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat() { -+ ReadOnlyScoreInfo scoreInfo = this.objective.checkState().board -+ .getPlayerScoreInfo(this.entry, this.objective.getHandle()); -+ -+ if (scoreInfo == null) { -+ return null; -+ } -+ -+ net.minecraft.network.chat.numbers.NumberFormat vanilla = scoreInfo.numberFormat(); -+ -+ if (vanilla == null) { -+ return null; -+ } -+ -+ return io.papermc.paper.util.PaperScoreboardFormat.asPaper(vanilla); -+ } -+ -+ -+ @Override -+ public void numberFormat(io.papermc.paper.scoreboard.numbers.NumberFormat format) { -+ final net.minecraft.world.scores.ScoreAccess access = this.objective.checkState() -+ .board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()); -+ -+ if (format == null) { -+ access.numberFormatOverride(null); -+ return; -+ } -+ -+ access.numberFormatOverride(io.papermc.paper.util.PaperScoreboardFormat.asVanilla(format)); -+ } -+ // Paper end - add number format -+ - @Override - public boolean isScoreSet() { - Scoreboard board = this.objective.checkState().board; diff --git a/patches/server/0923-improve-BanList-types.patch b/patches/server/0923-improve-BanList-types.patch new file mode 100644 index 0000000000..c89914131f --- /dev/null +++ b/patches/server/0923-improve-BanList-types.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yannick Lamprecht +Date: Sat, 10 Feb 2024 20:50:01 +0100 +Subject: [PATCH] improve BanList types + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index a2c749b2997557fec5c978f3bed8c35d7614e740..6136037d3d096300d93b9710dd854224b30e0738 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2260,6 +2260,21 @@ public final class CraftServer implements Server { + }; + } + ++ // Paper start - add BanListType (which has a generic) ++ @SuppressWarnings("unchecked") ++ @Override ++ public , E> B getBanList(final io.papermc.paper.ban.BanListType type) { ++ Preconditions.checkArgument(type != null, "BanList.BanType cannot be null"); ++ if (type == io.papermc.paper.ban.BanListType.IP) { ++ return (B) new CraftIpBanList(this.playerList.getIpBans()); ++ } else if (type == io.papermc.paper.ban.BanListType.PROFILE) { ++ return (B) new CraftProfileBanList(this.playerList.getBans()); ++ } else { ++ throw new IllegalArgumentException("Unknown BanListType: " + type); ++ } ++ } ++ // Paper end - add BanListType (which has a generic) ++ + @Override + public void setWhitelist(boolean value) { + this.playerList.setUsingWhiteList(value); diff --git a/patches/server/0924-Expanded-Hopper-API.patch b/patches/server/0924-Expanded-Hopper-API.patch new file mode 100644 index 0000000000..2b59ac9974 --- /dev/null +++ b/patches/server/0924-Expanded-Hopper-API.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: vicisacat +Date: Fri, 15 Mar 2024 17:35:40 +0100 +Subject: [PATCH] Expanded Hopper API + +== AT == +public net.minecraft.world.level.block.entity.HopperBlockEntity setCooldown(I)V +public net.minecraft.world.level.block.entity.HopperBlockEntity cooldownTime + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java +index 2995b407415c77288a54c3f4eb8cb93e1a289283..f3c4d3835a18475e2cd2f519ac3dd9d9b59c454d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java +@@ -40,4 +40,17 @@ public class CraftHopper extends CraftLootable implements Hop + public CraftHopper copy(Location location) { + return new CraftHopper(this, location); + } ++ ++ // Paper start - Expanded Hopper API ++ @Override ++ public void setTransferCooldown(final int cooldown) { ++ com.google.common.base.Preconditions.checkArgument(cooldown >= 0, "Hooper transfer cooldown cannot be negative (" + cooldown + ")"); ++ getSnapshot().setCooldown(cooldown); ++ } ++ ++ @Override ++ public int getTransferCooldown() { ++ return getSnapshot().cooldownTime; ++ } ++ // Paper end - Expanded Hopper API + } diff --git a/patches/server/0924-improve-BanList-types.patch b/patches/server/0924-improve-BanList-types.patch deleted file mode 100644 index 96871b48ee..0000000000 --- a/patches/server/0924-improve-BanList-types.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Yannick Lamprecht -Date: Sat, 10 Feb 2024 20:50:01 +0100 -Subject: [PATCH] improve BanList types - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 581a15957478fd9f394a27269c2bd68a117ad8c2..f7e478a14ef17ad6d747d0ab56418b0b5b20492d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2261,6 +2261,21 @@ public final class CraftServer implements Server { - }; - } - -+ // Paper start - add BanListType (which has a generic) -+ @SuppressWarnings("unchecked") -+ @Override -+ public , E> B getBanList(final io.papermc.paper.ban.BanListType type) { -+ Preconditions.checkArgument(type != null, "BanList.BanType cannot be null"); -+ if (type == io.papermc.paper.ban.BanListType.IP) { -+ return (B) new CraftIpBanList(this.playerList.getIpBans()); -+ } else if (type == io.papermc.paper.ban.BanListType.PROFILE) { -+ return (B) new CraftProfileBanList(this.playerList.getBans()); -+ } else { -+ throw new IllegalArgumentException("Unknown BanListType: " + type); -+ } -+ } -+ // Paper end - add BanListType (which has a generic) -+ - @Override - public void setWhitelist(boolean value) { - this.playerList.setUsingWhiteList(value); diff --git a/patches/server/0925-Add-BlockBreakProgressUpdateEvent.patch b/patches/server/0925-Add-BlockBreakProgressUpdateEvent.patch new file mode 100644 index 0000000000..9b57c89df5 --- /dev/null +++ b/patches/server/0925-Add-BlockBreakProgressUpdateEvent.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Badbird5907 <50347938+Badbird5907@users.noreply.github.com> +Date: Mon, 4 Mar 2024 22:18:28 -0500 +Subject: [PATCH] Add BlockBreakProgressUpdateEvent + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 7a985c30a973efacf3e8b70e7163c550d86b0870..ea1281c9a3b83b17de64d583e029db9bacabcd88 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1285,6 +1285,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (entity instanceof Player) entityhuman = (Player) entity; + // CraftBukkit end + ++ // Paper start - Add BlockBreakProgressUpdateEvent ++ // If a plugin is using this method to send destroy packets for a client-side only entity id, no block progress occurred on the server. ++ // Hence, do not call the event. ++ if (entity != null) { ++ float progressFloat = Mth.clamp(progress, 0, 10) / 10.0f; ++ org.bukkit.craftbukkit.block.CraftBlock bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(this, pos); ++ new io.papermc.paper.event.block.BlockBreakProgressUpdateEvent(bukkitBlock, progressFloat, entity.getBukkitEntity()) ++ .callEvent(); ++ } ++ // Paper end - Add BlockBreakProgressUpdateEvent ++ + while (iterator.hasNext()) { + ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + diff --git a/patches/server/0925-Expanded-Hopper-API.patch b/patches/server/0925-Expanded-Hopper-API.patch deleted file mode 100644 index 2b59ac9974..0000000000 --- a/patches/server/0925-Expanded-Hopper-API.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: vicisacat -Date: Fri, 15 Mar 2024 17:35:40 +0100 -Subject: [PATCH] Expanded Hopper API - -== AT == -public net.minecraft.world.level.block.entity.HopperBlockEntity setCooldown(I)V -public net.minecraft.world.level.block.entity.HopperBlockEntity cooldownTime - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java -index 2995b407415c77288a54c3f4eb8cb93e1a289283..f3c4d3835a18475e2cd2f519ac3dd9d9b59c454d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java -@@ -40,4 +40,17 @@ public class CraftHopper extends CraftLootable implements Hop - public CraftHopper copy(Location location) { - return new CraftHopper(this, location); - } -+ -+ // Paper start - Expanded Hopper API -+ @Override -+ public void setTransferCooldown(final int cooldown) { -+ com.google.common.base.Preconditions.checkArgument(cooldown >= 0, "Hooper transfer cooldown cannot be negative (" + cooldown + ")"); -+ getSnapshot().setCooldown(cooldown); -+ } -+ -+ @Override -+ public int getTransferCooldown() { -+ return getSnapshot().cooldownTime; -+ } -+ // Paper end - Expanded Hopper API - } diff --git a/patches/server/0926-Add-BlockBreakProgressUpdateEvent.patch b/patches/server/0926-Add-BlockBreakProgressUpdateEvent.patch deleted file mode 100644 index 2c5061f42f..0000000000 --- a/patches/server/0926-Add-BlockBreakProgressUpdateEvent.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Badbird5907 <50347938+Badbird5907@users.noreply.github.com> -Date: Mon, 4 Mar 2024 22:18:28 -0500 -Subject: [PATCH] Add BlockBreakProgressUpdateEvent - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a628da8a0ed7ae2c7b46df3881bd75dc5b4fd607..99e6021bc0dc5775f4443bdb77debd535a2cf29f 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1315,6 +1315,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (entity instanceof Player) entityhuman = (Player) entity; - // CraftBukkit end - -+ // Paper start - Add BlockBreakProgressUpdateEvent -+ // If a plugin is using this method to send destroy packets for a client-side only entity id, no block progress occurred on the server. -+ // Hence, do not call the event. -+ if (entity != null) { -+ float progressFloat = Mth.clamp(progress, 0, 10) / 10.0f; -+ org.bukkit.craftbukkit.block.CraftBlock bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(this, pos); -+ new io.papermc.paper.event.block.BlockBreakProgressUpdateEvent(bukkitBlock, progressFloat, entity.getBukkitEntity()) -+ .callEvent(); -+ } -+ // Paper end - Add BlockBreakProgressUpdateEvent -+ - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - diff --git a/patches/server/0926-Deprecate-ItemStack-setType.patch b/patches/server/0926-Deprecate-ItemStack-setType.patch new file mode 100644 index 0000000000..e58b22013f --- /dev/null +++ b/patches/server/0926-Deprecate-ItemStack-setType.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 26 Mar 2024 21:42:23 -0400 +Subject: [PATCH] Deprecate ItemStack#setType + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index ffd7ba14be38a117f5a7d7035a8d71a20fb1c4fc..7228d43d331de16cbaa0e97c7e3fa45c0bc89558 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -429,4 +429,24 @@ public final class CraftItemStack extends ItemStack { + static boolean hasItemMeta(net.minecraft.world.item.ItemStack item) { + return !(item == null || item.getComponentsPatch().isEmpty()); + } ++ // Paper start - with type ++ @Override ++ public ItemStack withType(final Material type) { ++ if (type == Material.AIR) { ++ return CraftItemStack.asCraftMirror(null); ++ } ++ ++ final net.minecraft.world.item.ItemStack copy = new net.minecraft.world.item.ItemStack( ++ CraftItemType.bukkitToMinecraft(type), this.getAmount() ++ ); ++ ++ if (this.handle != null) { ++ copy.applyComponents(this.handle.getComponentsPatch()); ++ } ++ ++ final CraftItemStack mirrored = CraftItemStack.asCraftMirror(copy); ++ mirrored.setItemMeta(mirrored.getItemMeta()); ++ return mirrored; ++ } ++ // Paper end + } diff --git a/patches/server/0927-Add-CartographyItemEvent.patch b/patches/server/0927-Add-CartographyItemEvent.patch new file mode 100644 index 0000000000..544bc15eda --- /dev/null +++ b/patches/server/0927-Add-CartographyItemEvent.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Janet Blackquill +Date: Sun, 7 Apr 2024 16:52:42 -0400 +Subject: [PATCH] Add CartographyItemEvent + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index f92624ccd43f448abdee92c975d613cbcb3457c6..90bed0a36b2d518b56164a414350ec02822ad42a 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3130,6 +3130,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + } + ++ // Paper start - cartography item event ++ if (packet.getSlotNum() == net.minecraft.world.inventory.CartographyTableMenu.RESULT_SLOT && top instanceof org.bukkit.inventory.CartographyInventory cartographyInventory) { ++ org.bukkit.inventory.ItemStack result = cartographyInventory.getResult(); ++ if (result != null && !result.isEmpty()) { ++ if (click == ClickType.NUMBER_KEY) { ++ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, packet.getSlotNum(), click, action, packet.getButtonNum()); ++ } else { ++ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, packet.getSlotNum(), click, action); ++ } ++ } ++ } ++ // Paper end - cartography item event ++ + event.setCancelled(cancelled); + AbstractContainerMenu oldContainer = this.player.containerMenu; // SPIGOT-1224 + this.cserver.getPluginManager().callEvent(event); +diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java +index b3a16b024e46ee8203b225ee429a5c973eab12c6..dc42d42ef91bc3e49f967c0a30a0d1b56e09cf21 100644 +--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java +@@ -71,7 +71,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { + this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders + @Override + public void setChanged() { +- CartographyTableMenu.this.slotsChanged(this); ++ // CartographyTableMenu.this.slotsChanged(this); // Paper - Add CatographyItemEvent - do not recompute results if the result slot changes - allows to set the result slot via api + super.setChanged(); + } + diff --git a/patches/server/0927-Deprecate-ItemStack-setType.patch b/patches/server/0927-Deprecate-ItemStack-setType.patch deleted file mode 100644 index e58b22013f..0000000000 --- a/patches/server/0927-Deprecate-ItemStack-setType.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Tue, 26 Mar 2024 21:42:23 -0400 -Subject: [PATCH] Deprecate ItemStack#setType - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index ffd7ba14be38a117f5a7d7035a8d71a20fb1c4fc..7228d43d331de16cbaa0e97c7e3fa45c0bc89558 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -429,4 +429,24 @@ public final class CraftItemStack extends ItemStack { - static boolean hasItemMeta(net.minecraft.world.item.ItemStack item) { - return !(item == null || item.getComponentsPatch().isEmpty()); - } -+ // Paper start - with type -+ @Override -+ public ItemStack withType(final Material type) { -+ if (type == Material.AIR) { -+ return CraftItemStack.asCraftMirror(null); -+ } -+ -+ final net.minecraft.world.item.ItemStack copy = new net.minecraft.world.item.ItemStack( -+ CraftItemType.bukkitToMinecraft(type), this.getAmount() -+ ); -+ -+ if (this.handle != null) { -+ copy.applyComponents(this.handle.getComponentsPatch()); -+ } -+ -+ final CraftItemStack mirrored = CraftItemStack.asCraftMirror(copy); -+ mirrored.setItemMeta(mirrored.getItemMeta()); -+ return mirrored; -+ } -+ // Paper end - } diff --git a/patches/server/0928-Add-CartographyItemEvent.patch b/patches/server/0928-Add-CartographyItemEvent.patch deleted file mode 100644 index b8a1377ce9..0000000000 --- a/patches/server/0928-Add-CartographyItemEvent.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Janet Blackquill -Date: Sun, 7 Apr 2024 16:52:42 -0400 -Subject: [PATCH] Add CartographyItemEvent - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 836e6b705b201253f2b81d1ca0228b8a0266a1dd..d3975496dcf94d3474e891bcd3105120559b6a61 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3133,6 +3133,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - } - -+ // Paper start - cartography item event -+ if (packet.getSlotNum() == net.minecraft.world.inventory.CartographyTableMenu.RESULT_SLOT && top instanceof org.bukkit.inventory.CartographyInventory cartographyInventory) { -+ org.bukkit.inventory.ItemStack result = cartographyInventory.getResult(); -+ if (result != null && !result.isEmpty()) { -+ if (click == ClickType.NUMBER_KEY) { -+ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, packet.getSlotNum(), click, action, packet.getButtonNum()); -+ } else { -+ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, packet.getSlotNum(), click, action); -+ } -+ } -+ } -+ // Paper end - cartography item event -+ - event.setCancelled(cancelled); - AbstractContainerMenu oldContainer = this.player.containerMenu; // SPIGOT-1224 - this.cserver.getPluginManager().callEvent(event); -diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -index b3a16b024e46ee8203b225ee429a5c973eab12c6..dc42d42ef91bc3e49f967c0a30a0d1b56e09cf21 100644 ---- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -@@ -71,7 +71,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { - this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders - @Override - public void setChanged() { -- CartographyTableMenu.this.slotsChanged(this); -+ // CartographyTableMenu.this.slotsChanged(this); // Paper - Add CatographyItemEvent - do not recompute results if the result slot changes - allows to set the result slot via api - super.setChanged(); - } - diff --git a/patches/server/0928-More-Raid-API.patch b/patches/server/0928-More-Raid-API.patch new file mode 100644 index 0000000000..2039ffa00d --- /dev/null +++ b/patches/server/0928-More-Raid-API.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 4 Mar 2022 09:46:33 -0800 +Subject: [PATCH] More Raid API + +== AT == +public net.minecraft.world.entity.raid.Raid raidEvent + +diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java +index 28922f2a1cf4762d5d7d09635b9268c6091300c3..11cf2d9def087b0898c828eaa21eb5f7b8811d5f 100644 +--- a/src/main/java/net/minecraft/world/entity/raid/Raid.java ++++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java +@@ -107,6 +107,11 @@ public class Raid { + private Raid.RaidStatus status; + private int celebrationTicks; + private Optional waveSpawnPos; ++ // Paper start ++ private static final String PDC_NBT_KEY = "BukkitValues"; ++ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry PDC_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); ++ public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(PDC_TYPE_REGISTRY); ++ // Paper end + + public Raid(int id, ServerLevel world, BlockPos pos) { + this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10); +@@ -150,6 +155,11 @@ public class Raid { + this.heroesOfTheVillage.add(NbtUtils.loadUUID(nbtbase)); + } + } ++ // Paper start ++ if (nbt.contains(PDC_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) { ++ this.persistentDataContainer.putAll(nbt.getCompound(PDC_NBT_KEY)); ++ } ++ // Paper end + + } + +@@ -862,6 +872,11 @@ public class Raid { + } + + nbt.put("HeroesOfTheVillage", nbttaglist); ++ // Paper start ++ if (!this.persistentDataContainer.isEmpty()) { ++ nbt.put(PDC_NBT_KEY, this.persistentDataContainer.toTagCompound()); ++ } ++ // Paper end + return nbt; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRaid.java b/src/main/java/org/bukkit/craftbukkit/CraftRaid.java +index b8ce1c1c2447f9cff1717bfcfd6eb911ade0d4b3..51f21af9d75769abdcba713b9aa33392e994d9b0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRaid.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRaid.java +@@ -103,4 +103,34 @@ public final class CraftRaid implements Raid { + public net.minecraft.world.entity.raid.Raid getHandle() { + return this.handle; + } ++ ++ // Paper start - more Raid API ++ @Override ++ public int getId() { ++ return this.handle.getId(); ++ } ++ ++ @Override ++ public org.bukkit.boss.BossBar getBossBar() { ++ return new org.bukkit.craftbukkit.boss.CraftBossBar(this.handle.raidEvent); ++ } ++ ++ @Override ++ public org.bukkit.persistence.PersistentDataContainer getPersistentDataContainer() { ++ return this.handle.persistentDataContainer; ++ } ++ ++ @Override ++ public boolean equals(final Object o) { ++ if (this == o) return true; ++ if (o == null || this.getClass() != o.getClass()) return false; ++ final org.bukkit.craftbukkit.CraftRaid craftRaid = (org.bukkit.craftbukkit.CraftRaid) o; ++ return this.handle.equals(craftRaid.handle); ++ } ++ ++ @Override ++ public int hashCode() { ++ return this.handle.hashCode(); ++ } ++ // Paper end - more Raid API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 34e8afae13085f0a9ce0c916d911c88c395418e0..406a3b4a6e213879a9b262d2ffa9ba404cf31cc1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -2326,6 +2326,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { + return (raid == null) ? null : new CraftRaid(raid); + } + ++ // Paper start - more Raid API ++ @Override ++ public @Nullable Raid getRaid(final int id) { ++ final net.minecraft.world.entity.raid.@Nullable Raid nmsRaid = this.world.getRaids().raidMap.get(id); ++ return nmsRaid != null ? new CraftRaid(nmsRaid) : null; ++ } ++ // Paper end - more Raid API ++ + @Override + public List getRaids() { + Raids persistentRaid = this.world.getRaids(); diff --git a/patches/server/0929-Add-onboarding-message-for-initial-server-start.patch b/patches/server/0929-Add-onboarding-message-for-initial-server-start.patch new file mode 100644 index 0000000000..73d18bd703 --- /dev/null +++ b/patches/server/0929-Add-onboarding-message-for-initial-server-start.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: leguan +Date: Sun, 10 Mar 2024 20:10:41 +0100 +Subject: [PATCH] Add onboarding message for initial server start + + +diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java +index d9502ba028a96f9cc846f9ed428bd8066b857ca3..87e5f614ba988547a827486740db217e28585773 100644 +--- a/src/main/java/io/papermc/paper/configuration/Configurations.java ++++ b/src/main/java/io/papermc/paper/configuration/Configurations.java +@@ -129,6 +129,7 @@ public abstract class Configurations { + if (Files.notExists(configFile)) { + node = CommentedConfigurationNode.root(loader.defaultOptions()); + node.node(Configuration.VERSION_FIELD).raw(this.globalConfigVersion()); ++ GlobalConfiguration.isFirstStart = true; + } else { + node = loader.load(); + this.verifyGlobalConfigVersion(node); +diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +index 56798215644d8bca1695856b3a941e8089f49e48..46c37c8db8ecf3cc808fcf59f6bee5fe6ca49b75 100644 +--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java ++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +@@ -25,6 +25,7 @@ public class GlobalConfiguration extends ConfigurationPart { + private static final Logger LOGGER = LogUtils.getLogger(); + static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): + private static GlobalConfiguration instance; ++ public static boolean isFirstStart = false; + public static GlobalConfiguration get() { + return instance; + } +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index be188079f12b3f7b394ae91db62cc17b1d0f4e79..2de0ae09de41f3ed254318a78d65045fc76e5016 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1149,6 +1149,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop " + onboardingLink + ""); ++ link.setFont(MinecraftServerGui.MONOSPACED); ++ link.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); ++ link.addMouseListener(new java.awt.event.MouseAdapter() { ++ @Override ++ public void mouseClicked(final java.awt.event.MouseEvent e) { ++ try { ++ java.awt.Desktop.getDesktop().browse(java.net.URI.create(onboardingLink)); ++ } catch (java.io.IOException exception) { ++ LOGGER.error("Unable to find a default browser. Please manually visit the website: " + onboardingLink, exception); ++ } catch (UnsupportedOperationException exception) { ++ LOGGER.error("This platform does not support the BROWSE action. Please manually visit the website: " + onboardingLink, exception); ++ } catch (SecurityException exception) { ++ LOGGER.error("This action has been denied by the security manager. Please manually visit the website: " + onboardingLink, exception); ++ } ++ } ++ }); ++ ++ jPanel.add(jLabel); ++ jPanel.add(link); ++ ++ return jPanel; ++ } ++ // Paper end - Add onboarding message for initial server start ++ + private JComponent buildPlayerPanel() { + JList jlist = new PlayerListComponent(this.server); + JScrollPane jscrollpane = new JScrollPane(jlist, 22, 30); diff --git a/patches/server/0929-More-Raid-API.patch b/patches/server/0929-More-Raid-API.patch deleted file mode 100644 index 2039ffa00d..0000000000 --- a/patches/server/0929-More-Raid-API.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 4 Mar 2022 09:46:33 -0800 -Subject: [PATCH] More Raid API - -== AT == -public net.minecraft.world.entity.raid.Raid raidEvent - -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java -index 28922f2a1cf4762d5d7d09635b9268c6091300c3..11cf2d9def087b0898c828eaa21eb5f7b8811d5f 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raid.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java -@@ -107,6 +107,11 @@ public class Raid { - private Raid.RaidStatus status; - private int celebrationTicks; - private Optional waveSpawnPos; -+ // Paper start -+ private static final String PDC_NBT_KEY = "BukkitValues"; -+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry PDC_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); -+ public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(PDC_TYPE_REGISTRY); -+ // Paper end - - public Raid(int id, ServerLevel world, BlockPos pos) { - this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10); -@@ -150,6 +155,11 @@ public class Raid { - this.heroesOfTheVillage.add(NbtUtils.loadUUID(nbtbase)); - } - } -+ // Paper start -+ if (nbt.contains(PDC_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) { -+ this.persistentDataContainer.putAll(nbt.getCompound(PDC_NBT_KEY)); -+ } -+ // Paper end - - } - -@@ -862,6 +872,11 @@ public class Raid { - } - - nbt.put("HeroesOfTheVillage", nbttaglist); -+ // Paper start -+ if (!this.persistentDataContainer.isEmpty()) { -+ nbt.put(PDC_NBT_KEY, this.persistentDataContainer.toTagCompound()); -+ } -+ // Paper end - return nbt; - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRaid.java b/src/main/java/org/bukkit/craftbukkit/CraftRaid.java -index b8ce1c1c2447f9cff1717bfcfd6eb911ade0d4b3..51f21af9d75769abdcba713b9aa33392e994d9b0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRaid.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRaid.java -@@ -103,4 +103,34 @@ public final class CraftRaid implements Raid { - public net.minecraft.world.entity.raid.Raid getHandle() { - return this.handle; - } -+ -+ // Paper start - more Raid API -+ @Override -+ public int getId() { -+ return this.handle.getId(); -+ } -+ -+ @Override -+ public org.bukkit.boss.BossBar getBossBar() { -+ return new org.bukkit.craftbukkit.boss.CraftBossBar(this.handle.raidEvent); -+ } -+ -+ @Override -+ public org.bukkit.persistence.PersistentDataContainer getPersistentDataContainer() { -+ return this.handle.persistentDataContainer; -+ } -+ -+ @Override -+ public boolean equals(final Object o) { -+ if (this == o) return true; -+ if (o == null || this.getClass() != o.getClass()) return false; -+ final org.bukkit.craftbukkit.CraftRaid craftRaid = (org.bukkit.craftbukkit.CraftRaid) o; -+ return this.handle.equals(craftRaid.handle); -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.handle.hashCode(); -+ } -+ // Paper end - more Raid API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 34e8afae13085f0a9ce0c916d911c88c395418e0..406a3b4a6e213879a9b262d2ffa9ba404cf31cc1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2326,6 +2326,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { - return (raid == null) ? null : new CraftRaid(raid); - } - -+ // Paper start - more Raid API -+ @Override -+ public @Nullable Raid getRaid(final int id) { -+ final net.minecraft.world.entity.raid.@Nullable Raid nmsRaid = this.world.getRaids().raidMap.get(id); -+ return nmsRaid != null ? new CraftRaid(nmsRaid) : null; -+ } -+ // Paper end - more Raid API -+ - @Override - public List getRaids() { - Raids persistentRaid = this.world.getRaids(); diff --git a/patches/server/0930-Add-onboarding-message-for-initial-server-start.patch b/patches/server/0930-Add-onboarding-message-for-initial-server-start.patch deleted file mode 100644 index 70718c71a4..0000000000 --- a/patches/server/0930-Add-onboarding-message-for-initial-server-start.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: leguan -Date: Sun, 10 Mar 2024 20:10:41 +0100 -Subject: [PATCH] Add onboarding message for initial server start - - -diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java -index d9502ba028a96f9cc846f9ed428bd8066b857ca3..87e5f614ba988547a827486740db217e28585773 100644 ---- a/src/main/java/io/papermc/paper/configuration/Configurations.java -+++ b/src/main/java/io/papermc/paper/configuration/Configurations.java -@@ -129,6 +129,7 @@ public abstract class Configurations { - if (Files.notExists(configFile)) { - node = CommentedConfigurationNode.root(loader.defaultOptions()); - node.node(Configuration.VERSION_FIELD).raw(this.globalConfigVersion()); -+ GlobalConfiguration.isFirstStart = true; - } else { - node = loader.load(); - this.verifyGlobalConfigVersion(node); -diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index 36b96e0ed5c0d25068ec4678eddd8a19a020d345..8a0cb603cd4dbfa1839e0f4e1606876cbb373277 100644 ---- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -27,6 +27,7 @@ public class GlobalConfiguration extends ConfigurationPart { - private static final Logger LOGGER = LogUtils.getLogger(); - static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): - private static GlobalConfiguration instance; -+ public static boolean isFirstStart = false; - public static GlobalConfiguration get() { - return instance; - } -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7e83a0de08488c5acf3c1a5d7107564e2a8ed7e0..6de199b7cf7728479fede534338829cecade50f2 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1151,6 +1151,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop " + onboardingLink + ""); -+ link.setFont(MinecraftServerGui.MONOSPACED); -+ link.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); -+ link.addMouseListener(new java.awt.event.MouseAdapter() { -+ @Override -+ public void mouseClicked(final java.awt.event.MouseEvent e) { -+ try { -+ java.awt.Desktop.getDesktop().browse(java.net.URI.create(onboardingLink)); -+ } catch (java.io.IOException exception) { -+ LOGGER.error("Unable to find a default browser. Please manually visit the website: " + onboardingLink, exception); -+ } catch (UnsupportedOperationException exception) { -+ LOGGER.error("This platform does not support the BROWSE action. Please manually visit the website: " + onboardingLink, exception); -+ } catch (SecurityException exception) { -+ LOGGER.error("This action has been denied by the security manager. Please manually visit the website: " + onboardingLink, exception); -+ } -+ } -+ }); -+ -+ jPanel.add(jLabel); -+ jPanel.add(link); -+ -+ return jPanel; -+ } -+ // Paper end - Add onboarding message for initial server start -+ - private JComponent buildPlayerPanel() { - JList jlist = new PlayerListComponent(this.server); - JScrollPane jscrollpane = new JScrollPane(jlist, 22, 30); diff --git a/patches/server/0930-Configurable-max-block-fluid-ticks.patch b/patches/server/0930-Configurable-max-block-fluid-ticks.patch new file mode 100644 index 0000000000..c93e0006cc --- /dev/null +++ b/patches/server/0930-Configurable-max-block-fluid-ticks.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gero +Date: Mon, 19 Feb 2024 17:39:59 +0100 +Subject: [PATCH] Configurable max block/fluid ticks + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index ea1281c9a3b83b17de64d583e029db9bacabcd88..711d5136124c0fa21015f0154057ab5742071e59 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -489,9 +489,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (!this.isDebug() && flag) { + j = this.getGameTime(); + gameprofilerfiller.push("blockTicks"); +- this.blockTicks.tick(j, 65536, this::tickBlock); ++ this.blockTicks.tick(j, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks + gameprofilerfiller.popPush("fluidTicks"); +- this.fluidTicks.tick(j, 65536, this::tickFluid); ++ this.fluidTicks.tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks + gameprofilerfiller.pop(); + } + diff --git a/patches/server/0931-Configurable-max-block-fluid-ticks.patch b/patches/server/0931-Configurable-max-block-fluid-ticks.patch deleted file mode 100644 index 15cd7fb486..0000000000 --- a/patches/server/0931-Configurable-max-block-fluid-ticks.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Gero -Date: Mon, 19 Feb 2024 17:39:59 +0100 -Subject: [PATCH] Configurable max block/fluid ticks - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 99e6021bc0dc5775f4443bdb77debd535a2cf29f..eed2d1ec425bbd34563fae9e69a4518ec154fc23 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -492,9 +492,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (!this.isDebug() && flag) { - j = this.getGameTime(); - gameprofilerfiller.push("blockTicks"); -- this.blockTicks.tick(j, 65536, this::tickBlock); -+ this.blockTicks.tick(j, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks - gameprofilerfiller.popPush("fluidTicks"); -- this.fluidTicks.tick(j, 65536, this::tickFluid); -+ this.fluidTicks.tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks - gameprofilerfiller.pop(); - } - this.timings.scheduledBlocks.stopTiming(); // Paper diff --git a/patches/server/0931-Fix-bees-aging-inside-hives.patch b/patches/server/0931-Fix-bees-aging-inside-hives.patch new file mode 100644 index 0000000000..8d4dcd0b64 --- /dev/null +++ b/patches/server/0931-Fix-bees-aging-inside-hives.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 21 Aug 2021 21:54:16 -0700 +Subject: [PATCH] Fix bees aging inside hives + +Fixes bees incorrectly being aged up due to upstream's +resetting the ticks inside hive on a failed release + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +index f8828dc8334af19d7b2118e8cf34d94be5e09ee8..83ad45aed0894e90825d22e078632352c3a06816 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +@@ -315,7 +315,7 @@ public class BeehiveBlockEntity extends BlockEntity { + iterator.remove(); + // CraftBukkit start + } else { +- tileentitybeehive_hivebee.ticksInHive = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable ++ tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - Fix bees aging inside hives; use exitTickCounter to keep actual bee life + // CraftBukkit end + } + } +@@ -475,15 +475,18 @@ public class BeehiveBlockEntity extends BlockEntity { + private static class BeeData { + + private final BeehiveBlockEntity.Occupant occupant; ++ private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts + private int ticksInHive; + + BeeData(BeehiveBlockEntity.Occupant data) { + this.occupant = data; + this.ticksInHive = data.ticksInHive(); ++ this.exitTickCounter = this.ticksInHive; // Paper - Fix bees aging inside hives + } + + public boolean tick() { +- return this.ticksInHive++ > this.occupant.minTicksInHive; ++ this.ticksInHive++; // Paper - Fix bees aging inside hives ++ return this.exitTickCounter++ > this.occupant.minTicksInHive; // Paper - Fix bees aging inside hives + } + + public BeehiveBlockEntity.Occupant toOccupant() { diff --git a/patches/server/0932-Disable-memory-reserve-allocating.patch b/patches/server/0932-Disable-memory-reserve-allocating.patch new file mode 100644 index 0000000000..ea801f5092 --- /dev/null +++ b/patches/server/0932-Disable-memory-reserve-allocating.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Thu, 18 Jan 2024 23:25:09 +0100 +Subject: [PATCH] Disable memory reserve allocating + + +diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java +index 268310642181a715815d3b2d1c0f090e6252971a..589a8bf75be6ccc59f1e5dd5d8d9afed41c4772d 100644 +--- a/src/main/java/net/minecraft/CrashReport.java ++++ b/src/main/java/net/minecraft/CrashReport.java +@@ -253,7 +253,7 @@ public class CrashReport { + } + + public static void preload() { +- MemoryReserve.allocate(); ++ // MemoryReserve.allocate(); // Paper - Disable memory reserve allocating + (new CrashReport("Don't panic!", new Throwable())).getFriendlyReport(ReportType.CRASH); + } + } diff --git a/patches/server/0932-Fix-bees-aging-inside-hives.patch b/patches/server/0932-Fix-bees-aging-inside-hives.patch deleted file mode 100644 index 8d4dcd0b64..0000000000 --- a/patches/server/0932-Fix-bees-aging-inside-hives.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 21 Aug 2021 21:54:16 -0700 -Subject: [PATCH] Fix bees aging inside hives - -Fixes bees incorrectly being aged up due to upstream's -resetting the ticks inside hive on a failed release - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index f8828dc8334af19d7b2118e8cf34d94be5e09ee8..83ad45aed0894e90825d22e078632352c3a06816 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -315,7 +315,7 @@ public class BeehiveBlockEntity extends BlockEntity { - iterator.remove(); - // CraftBukkit start - } else { -- tileentitybeehive_hivebee.ticksInHive = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable -+ tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - Fix bees aging inside hives; use exitTickCounter to keep actual bee life - // CraftBukkit end - } - } -@@ -475,15 +475,18 @@ public class BeehiveBlockEntity extends BlockEntity { - private static class BeeData { - - private final BeehiveBlockEntity.Occupant occupant; -+ private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts - private int ticksInHive; - - BeeData(BeehiveBlockEntity.Occupant data) { - this.occupant = data; - this.ticksInHive = data.ticksInHive(); -+ this.exitTickCounter = this.ticksInHive; // Paper - Fix bees aging inside hives - } - - public boolean tick() { -- return this.ticksInHive++ > this.occupant.minTicksInHive; -+ this.ticksInHive++; // Paper - Fix bees aging inside hives -+ return this.exitTickCounter++ > this.occupant.minTicksInHive; // Paper - Fix bees aging inside hives - } - - public BeehiveBlockEntity.Occupant toOccupant() { diff --git a/patches/server/0933-Disable-memory-reserve-allocating.patch b/patches/server/0933-Disable-memory-reserve-allocating.patch deleted file mode 100644 index ea801f5092..0000000000 --- a/patches/server/0933-Disable-memory-reserve-allocating.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Warrior <50800980+Warriorrrr@users.noreply.github.com> -Date: Thu, 18 Jan 2024 23:25:09 +0100 -Subject: [PATCH] Disable memory reserve allocating - - -diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java -index 268310642181a715815d3b2d1c0f090e6252971a..589a8bf75be6ccc59f1e5dd5d8d9afed41c4772d 100644 ---- a/src/main/java/net/minecraft/CrashReport.java -+++ b/src/main/java/net/minecraft/CrashReport.java -@@ -253,7 +253,7 @@ public class CrashReport { - } - - public static void preload() { -- MemoryReserve.allocate(); -+ // MemoryReserve.allocate(); // Paper - Disable memory reserve allocating - (new CrashReport("Don't panic!", new Throwable())).getFriendlyReport(ReportType.CRASH); - } - } diff --git a/patches/server/0933-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch b/patches/server/0933-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch new file mode 100644 index 0000000000..3cf04503d8 --- /dev/null +++ b/patches/server/0933-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com> +Date: Sun, 11 Feb 2024 20:05:11 +0100 +Subject: [PATCH] Fire EntityDamageByEntityEvent for unowned wither skulls + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java +index 8c17bed56c4659a8e226e88e113884160c3fa959..8831af1000d17d5a60302e3b0c522b2d2f082484 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java +@@ -77,7 +77,7 @@ public class WitherSkull extends AbstractHurtingProjectile { + } + } + } else { +- flag = entity.hurtServer(worldserver, this.damageSources().magic(), 5.0F); ++ flag = entity.hurtServer(worldserver, this.damageSources().magic().customCausingEntity(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls + } + + if (flag && entity instanceof LivingEntity entityliving) { diff --git a/patches/server/0934-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch b/patches/server/0934-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch deleted file mode 100644 index 3cf04503d8..0000000000 --- a/patches/server/0934-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com> -Date: Sun, 11 Feb 2024 20:05:11 +0100 -Subject: [PATCH] Fire EntityDamageByEntityEvent for unowned wither skulls - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -index 8c17bed56c4659a8e226e88e113884160c3fa959..8831af1000d17d5a60302e3b0c522b2d2f082484 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -@@ -77,7 +77,7 @@ public class WitherSkull extends AbstractHurtingProjectile { - } - } - } else { -- flag = entity.hurtServer(worldserver, this.damageSources().magic(), 5.0F); -+ flag = entity.hurtServer(worldserver, this.damageSources().magic().customCausingEntity(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls - } - - if (flag && entity instanceof LivingEntity entityliving) { diff --git a/patches/server/0934-Fix-DamageSource-API.patch b/patches/server/0934-Fix-DamageSource-API.patch new file mode 100644 index 0000000000..113d204bee --- /dev/null +++ b/patches/server/0934-Fix-DamageSource-API.patch @@ -0,0 +1,234 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 9 Mar 2024 14:13:04 -0800 +Subject: [PATCH] Fix DamageSource API + +Uses the correct entity in the EntityDamageByEntity event +Returns the correct entity for API's DamageSource#getCausingEntity + +diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java +index aee26dd78953ff43306aaa64161f5b9edcdd4b83..bb1a60180e58c1333e7bb33e8acf1b0225eda8a8 100644 +--- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java ++++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java +@@ -29,8 +29,8 @@ public class DamageSource { + private boolean sweep = false; + private boolean melting = false; + private boolean poison = false; +- private Entity customEntityDamager = null; // This field is a helper for when direct entity damage is not set by vanilla +- private Entity customCausingEntityDamager = null; // This field is a helper for when causing entity damage is not set by vanilla ++ @Nullable ++ private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API + + public DamageSource sweep() { + this.sweep = true; +@@ -59,33 +59,19 @@ public class DamageSource { + return this.poison; + } + +- public Entity getDamager() { +- return (this.customEntityDamager != null) ? this.customEntityDamager : this.directEntity; +- } +- +- public Entity getCausingDamager() { +- return (this.customCausingEntityDamager != null) ? this.customCausingEntityDamager : this.causingEntity; +- } +- +- public DamageSource customEntityDamager(Entity entity) { +- // This method is not intended for change the causing entity if is already set +- // also is only necessary if the entity passed is not the direct entity or different from the current causingEntity +- if (this.customEntityDamager != null || this.directEntity == entity || this.causingEntity == entity) { +- return this; +- } +- DamageSource damageSource = this.cloneInstance(); +- damageSource.customEntityDamager = entity; +- return damageSource; ++ // Paper start - fix DamageSource API ++ @Nullable ++ public Entity getCustomEventDamager() { ++ return (this.customEventDamager != null) ? this.customEventDamager : this.directEntity; + } + +- public DamageSource customCausingEntityDamager(Entity entity) { +- // This method is not intended for change the causing entity if is already set +- // also is only necessary if the entity passed is not the direct entity or different from the current causingEntity +- if (this.customCausingEntityDamager != null || this.directEntity == entity || this.causingEntity == entity) { +- return this; ++ public DamageSource customEventDamager(Entity entity) { ++ if (this.directEntity != null) { ++ throw new IllegalStateException("Cannot set custom event damager when direct entity is already set (report a bug to Paper)"); + } + DamageSource damageSource = this.cloneInstance(); +- damageSource.customCausingEntityDamager = entity; ++ damageSource.customEventDamager = entity; ++ // Paper end - fix DamageSource API + return damageSource; + } + +diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java +index fddbdb7322a2063996a28c5c3d93c265188b1256..be87cb3cfa15a7d889118cdc4b87232e30749023 100644 +--- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java ++++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java +@@ -270,13 +270,7 @@ public class DamageSources { + } + + public DamageSource explosion(@Nullable Entity source, @Nullable Entity attacker) { +- // CraftBukkit start +- return this.explosion(source, attacker, attacker != null && source != null ? DamageTypes.PLAYER_EXPLOSION : DamageTypes.EXPLOSION); +- } +- +- public DamageSource explosion(@Nullable Entity entity, @Nullable Entity entity1, ResourceKey resourceKey) { +- return this.source(resourceKey, entity, entity1); +- // CraftBukkit end ++ return this.source(attacker != null && source != null ? DamageTypes.PLAYER_EXPLOSION : DamageTypes.EXPLOSION, source, attacker); // Paper - revert to vanilla + } + + public DamageSource sonicBoom(Entity attacker) { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index cdc5ea3dd9559c076049c86a9fdb4e8bf85ff6c0..23095ace5a6aa6fd6cc1d5defa4a783ccb637b1d 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3388,7 +3388,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return; + } + +- if (!this.hurtServer(world, this.damageSources().lightningBolt().customEntityDamager(lightning), 5.0F)) { ++ if (!this.hurtServer(world, this.damageSources().lightningBolt().customEventDamager(lightning), 5.0F)) { // Paper - fix DamageSource API + return; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java +index 9a9ecc3e2c176c6d9700c4c585250b9780b7629b..d6605c15111dbdb6ee61a24822bc0a9aed7198d6 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java +@@ -341,7 +341,7 @@ public class Turtle extends Animal { + + @Override + public void thunderHit(ServerLevel world, LightningBolt lightning) { +- this.hurtServer(world, this.damageSources().lightningBolt().customEntityDamager(lightning), Float.MAX_VALUE); // CraftBukkit ++ this.hurtServer(world, this.damageSources().lightningBolt().customEventDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java +index 608acb4f3cb8f9a0dc10b819ed4bf577c229dd2c..7ed127a0a0c0d6e7b726216c48ef37af4db37628 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java +@@ -108,7 +108,7 @@ public abstract class BlockAttachedEntity extends Entity { + } else { + if (!this.isRemoved()) { + // CraftBukkit start - fire break events +- Entity damager = (source.isDirect()) ? source.getDirectEntity() : source.getEntity(); ++ Entity damager = (!source.isDirect() && source.getEntity() != null) ? source.getEntity() : source.getDirectEntity(); // Paper - fix DamageSource API + HangingBreakEvent event; + if (damager != null) { + event = new HangingBreakByEntityEvent((Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), source.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.ENTITY); +diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java +index 7a18dc59aed5294cd442994aa2d34ea00b877f46..1906dfc22af208d6e801ad4a8f2f9e9702432691 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java +@@ -271,7 +271,7 @@ public class Creeper extends Monster { + if (!event.isCancelled()) { + // CraftBukkit end + this.dead = true; +- worldserver.explode(this, net.minecraft.world.level.Explosion.getDefaultDamageSource(this.level(), this).customCausingEntityDamager(this.entityIgniter), null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit ++ worldserver.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) + this.spawnLingeringCloud(); + this.triggerOnDeathMobEffects(worldserver, Entity.RemovalReason.KILLED); + this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java b/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java +index c08074d43d105b30ed5093614062a3bcafadfb74..ccc72a2cf02a633655b95f961be310879d8f904f 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java +@@ -135,7 +135,7 @@ public class EvokerFangs extends Entity implements TraceableEntity { + + if (target.isAlive() && !target.isInvulnerable() && target != entityliving1) { + if (entityliving1 == null) { +- target.hurt(this.damageSources().magic().customEntityDamager(this), 6.0F); // CraftBukkit ++ target.hurt(this.damageSources().magic().customEventDamager(this), 6.0F); // CraftBukkit // Paper - fix DamageSource API + } else { + if (entityliving1.isAlliedTo((Entity) target)) { + return; +diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +index 080d886008e1f596733ea5331b32db35adef2e9b..5f790dd24f2bdae827c6dc597064b9b265089751 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +@@ -170,7 +170,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { + if (entityplayer1 != null) { + entityplayer1.resetFallDistance(); + entityplayer1.resetCurrentImpulseContext(); +- entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEntityDamager(this), 5.0F); // CraftBukkit ++ entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API + } + + this.playSound(worldserver, vec3d); +diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java +index 8831af1000d17d5a60302e3b0c522b2d2f082484..4c47b30867e30d84908abf93dbefc252bc8c3453 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java +@@ -77,7 +77,7 @@ public class WitherSkull extends AbstractHurtingProjectile { + } + } + } else { +- flag = entity.hurtServer(worldserver, this.damageSources().magic().customCausingEntity(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls ++ flag = entity.hurtServer(worldserver, this.damageSources().magic().customEventDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API + } + + if (flag && entity instanceof LivingEntity entityliving) { +diff --git a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java +index 8532324060eed772a10e2a3429890438cf32f9ba..7df86e7124a9ed359f05324b8fc4c8862f7e4b79 100644 +--- a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java ++++ b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java +@@ -41,13 +41,13 @@ public class CraftDamageSource implements DamageSource { + + @Override + public org.bukkit.entity.Entity getCausingEntity() { +- net.minecraft.world.entity.Entity entity = this.getHandle().getCausingDamager(); ++ net.minecraft.world.entity.Entity entity = this.getHandle().getEntity(); // Paper - fix DamageSource API - revert to vanilla + return (entity != null) ? entity.getBukkitEntity() : null; + } + + @Override + public org.bukkit.entity.Entity getDirectEntity() { +- net.minecraft.world.entity.Entity entity = this.getHandle().getDamager(); ++ net.minecraft.world.entity.Entity entity = this.getHandle().getDirectEntity(); // Paper - fix DamageSource API + return (entity != null) ? entity.getBukkitEntity() : null; + } + +@@ -65,7 +65,7 @@ public class CraftDamageSource implements DamageSource { + + @Override + public boolean isIndirect() { +- return this.getHandle().getCausingDamager() != this.getHandle().getDamager(); ++ return !this.getHandle().isDirect(); // Paper - fix DamageSource API + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java +index 4c6e15535fa40aad8cf1920f392589404f9ba79c..35eb95ef6fb6a0f7ea63351e90741c489fdd15f9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java ++++ b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java +@@ -41,6 +41,11 @@ public class CraftDamageSourceBuilder implements DamageSource.Builder { + + @Override + public DamageSource build() { ++ // Paper start - fix DamageCause API ++ if (this.causingEntity != null && this.directEntity == null) { ++ throw new IllegalArgumentException("Direct entity must be set if causing entity is set"); ++ } ++ // Paper end - fix DamageCause API + return CraftDamageSource.buildFromBukkit(this.damageType, this.causingEntity, this.directEntity, this.damageLocation); + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index e7749a3ef6289d73379649f2f76f4e4fdfac7a8b..96b901d07718d8926a2175925e867b4417c3947c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1092,7 +1092,7 @@ public class CraftEventFactory { + + private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSource source, Map modifiers, Map> modifierFunctions, boolean cancelled) { + CraftDamageSource bukkitDamageSource = new CraftDamageSource(source); +- Entity damager = (source.getDamager() != null) ? source.getDamager() : source.getEntity(); ++ final Entity damager = source.getCustomEventDamager(); // Paper - fix DamageSource API + if (source.is(DamageTypeTags.IS_EXPLOSION)) { + if (damager == null) { + return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.BLOCK_EXPLOSION, bukkitDamageSource, modifiers, modifierFunctions, cancelled); diff --git a/patches/server/0935-Fix-DamageSource-API.patch b/patches/server/0935-Fix-DamageSource-API.patch deleted file mode 100644 index 113d204bee..0000000000 --- a/patches/server/0935-Fix-DamageSource-API.patch +++ /dev/null @@ -1,234 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 9 Mar 2024 14:13:04 -0800 -Subject: [PATCH] Fix DamageSource API - -Uses the correct entity in the EntityDamageByEntity event -Returns the correct entity for API's DamageSource#getCausingEntity - -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index aee26dd78953ff43306aaa64161f5b9edcdd4b83..bb1a60180e58c1333e7bb33e8acf1b0225eda8a8 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -29,8 +29,8 @@ public class DamageSource { - private boolean sweep = false; - private boolean melting = false; - private boolean poison = false; -- private Entity customEntityDamager = null; // This field is a helper for when direct entity damage is not set by vanilla -- private Entity customCausingEntityDamager = null; // This field is a helper for when causing entity damage is not set by vanilla -+ @Nullable -+ private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API - - public DamageSource sweep() { - this.sweep = true; -@@ -59,33 +59,19 @@ public class DamageSource { - return this.poison; - } - -- public Entity getDamager() { -- return (this.customEntityDamager != null) ? this.customEntityDamager : this.directEntity; -- } -- -- public Entity getCausingDamager() { -- return (this.customCausingEntityDamager != null) ? this.customCausingEntityDamager : this.causingEntity; -- } -- -- public DamageSource customEntityDamager(Entity entity) { -- // This method is not intended for change the causing entity if is already set -- // also is only necessary if the entity passed is not the direct entity or different from the current causingEntity -- if (this.customEntityDamager != null || this.directEntity == entity || this.causingEntity == entity) { -- return this; -- } -- DamageSource damageSource = this.cloneInstance(); -- damageSource.customEntityDamager = entity; -- return damageSource; -+ // Paper start - fix DamageSource API -+ @Nullable -+ public Entity getCustomEventDamager() { -+ return (this.customEventDamager != null) ? this.customEventDamager : this.directEntity; - } - -- public DamageSource customCausingEntityDamager(Entity entity) { -- // This method is not intended for change the causing entity if is already set -- // also is only necessary if the entity passed is not the direct entity or different from the current causingEntity -- if (this.customCausingEntityDamager != null || this.directEntity == entity || this.causingEntity == entity) { -- return this; -+ public DamageSource customEventDamager(Entity entity) { -+ if (this.directEntity != null) { -+ throw new IllegalStateException("Cannot set custom event damager when direct entity is already set (report a bug to Paper)"); - } - DamageSource damageSource = this.cloneInstance(); -- damageSource.customCausingEntityDamager = entity; -+ damageSource.customEventDamager = entity; -+ // Paper end - fix DamageSource API - return damageSource; - } - -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java -index fddbdb7322a2063996a28c5c3d93c265188b1256..be87cb3cfa15a7d889118cdc4b87232e30749023 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java -@@ -270,13 +270,7 @@ public class DamageSources { - } - - public DamageSource explosion(@Nullable Entity source, @Nullable Entity attacker) { -- // CraftBukkit start -- return this.explosion(source, attacker, attacker != null && source != null ? DamageTypes.PLAYER_EXPLOSION : DamageTypes.EXPLOSION); -- } -- -- public DamageSource explosion(@Nullable Entity entity, @Nullable Entity entity1, ResourceKey resourceKey) { -- return this.source(resourceKey, entity, entity1); -- // CraftBukkit end -+ return this.source(attacker != null && source != null ? DamageTypes.PLAYER_EXPLOSION : DamageTypes.EXPLOSION, source, attacker); // Paper - revert to vanilla - } - - public DamageSource sonicBoom(Entity attacker) { -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index cdc5ea3dd9559c076049c86a9fdb4e8bf85ff6c0..23095ace5a6aa6fd6cc1d5defa4a783ccb637b1d 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3388,7 +3388,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return; - } - -- if (!this.hurtServer(world, this.damageSources().lightningBolt().customEntityDamager(lightning), 5.0F)) { -+ if (!this.hurtServer(world, this.damageSources().lightningBolt().customEventDamager(lightning), 5.0F)) { // Paper - fix DamageSource API - return; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index 9a9ecc3e2c176c6d9700c4c585250b9780b7629b..d6605c15111dbdb6ee61a24822bc0a9aed7198d6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -341,7 +341,7 @@ public class Turtle extends Animal { - - @Override - public void thunderHit(ServerLevel world, LightningBolt lightning) { -- this.hurtServer(world, this.damageSources().lightningBolt().customEntityDamager(lightning), Float.MAX_VALUE); // CraftBukkit -+ this.hurtServer(world, this.damageSources().lightningBolt().customEventDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java -index 608acb4f3cb8f9a0dc10b819ed4bf577c229dd2c..7ed127a0a0c0d6e7b726216c48ef37af4db37628 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java -@@ -108,7 +108,7 @@ public abstract class BlockAttachedEntity extends Entity { - } else { - if (!this.isRemoved()) { - // CraftBukkit start - fire break events -- Entity damager = (source.isDirect()) ? source.getDirectEntity() : source.getEntity(); -+ Entity damager = (!source.isDirect() && source.getEntity() != null) ? source.getEntity() : source.getDirectEntity(); // Paper - fix DamageSource API - HangingBreakEvent event; - if (damager != null) { - event = new HangingBreakByEntityEvent((Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), source.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.ENTITY); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index 7a18dc59aed5294cd442994aa2d34ea00b877f46..1906dfc22af208d6e801ad4a8f2f9e9702432691 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -271,7 +271,7 @@ public class Creeper extends Monster { - if (!event.isCancelled()) { - // CraftBukkit end - this.dead = true; -- worldserver.explode(this, net.minecraft.world.level.Explosion.getDefaultDamageSource(this.level(), this).customCausingEntityDamager(this.entityIgniter), null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit -+ worldserver.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) - this.spawnLingeringCloud(); - this.triggerOnDeathMobEffects(worldserver, Entity.RemovalReason.KILLED); - this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause -diff --git a/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java b/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java -index c08074d43d105b30ed5093614062a3bcafadfb74..ccc72a2cf02a633655b95f961be310879d8f904f 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java -@@ -135,7 +135,7 @@ public class EvokerFangs extends Entity implements TraceableEntity { - - if (target.isAlive() && !target.isInvulnerable() && target != entityliving1) { - if (entityliving1 == null) { -- target.hurt(this.damageSources().magic().customEntityDamager(this), 6.0F); // CraftBukkit -+ target.hurt(this.damageSources().magic().customEventDamager(this), 6.0F); // CraftBukkit // Paper - fix DamageSource API - } else { - if (entityliving1.isAlliedTo((Entity) target)) { - return; -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -index 080d886008e1f596733ea5331b32db35adef2e9b..5f790dd24f2bdae827c6dc597064b9b265089751 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -@@ -170,7 +170,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { - if (entityplayer1 != null) { - entityplayer1.resetFallDistance(); - entityplayer1.resetCurrentImpulseContext(); -- entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEntityDamager(this), 5.0F); // CraftBukkit -+ entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API - } - - this.playSound(worldserver, vec3d); -diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -index 8831af1000d17d5a60302e3b0c522b2d2f082484..4c47b30867e30d84908abf93dbefc252bc8c3453 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -@@ -77,7 +77,7 @@ public class WitherSkull extends AbstractHurtingProjectile { - } - } - } else { -- flag = entity.hurtServer(worldserver, this.damageSources().magic().customCausingEntity(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls -+ flag = entity.hurtServer(worldserver, this.damageSources().magic().customEventDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API - } - - if (flag && entity instanceof LivingEntity entityliving) { -diff --git a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java -index 8532324060eed772a10e2a3429890438cf32f9ba..7df86e7124a9ed359f05324b8fc4c8862f7e4b79 100644 ---- a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java -+++ b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java -@@ -41,13 +41,13 @@ public class CraftDamageSource implements DamageSource { - - @Override - public org.bukkit.entity.Entity getCausingEntity() { -- net.minecraft.world.entity.Entity entity = this.getHandle().getCausingDamager(); -+ net.minecraft.world.entity.Entity entity = this.getHandle().getEntity(); // Paper - fix DamageSource API - revert to vanilla - return (entity != null) ? entity.getBukkitEntity() : null; - } - - @Override - public org.bukkit.entity.Entity getDirectEntity() { -- net.minecraft.world.entity.Entity entity = this.getHandle().getDamager(); -+ net.minecraft.world.entity.Entity entity = this.getHandle().getDirectEntity(); // Paper - fix DamageSource API - return (entity != null) ? entity.getBukkitEntity() : null; - } - -@@ -65,7 +65,7 @@ public class CraftDamageSource implements DamageSource { - - @Override - public boolean isIndirect() { -- return this.getHandle().getCausingDamager() != this.getHandle().getDamager(); -+ return !this.getHandle().isDirect(); // Paper - fix DamageSource API - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java -index 4c6e15535fa40aad8cf1920f392589404f9ba79c..35eb95ef6fb6a0f7ea63351e90741c489fdd15f9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java -+++ b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java -@@ -41,6 +41,11 @@ public class CraftDamageSourceBuilder implements DamageSource.Builder { - - @Override - public DamageSource build() { -+ // Paper start - fix DamageCause API -+ if (this.causingEntity != null && this.directEntity == null) { -+ throw new IllegalArgumentException("Direct entity must be set if causing entity is set"); -+ } -+ // Paper end - fix DamageCause API - return CraftDamageSource.buildFromBukkit(this.damageType, this.causingEntity, this.directEntity, this.damageLocation); - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index e7749a3ef6289d73379649f2f76f4e4fdfac7a8b..96b901d07718d8926a2175925e867b4417c3947c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1092,7 +1092,7 @@ public class CraftEventFactory { - - private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSource source, Map modifiers, Map> modifierFunctions, boolean cancelled) { - CraftDamageSource bukkitDamageSource = new CraftDamageSource(source); -- Entity damager = (source.getDamager() != null) ? source.getDamager() : source.getEntity(); -+ final Entity damager = source.getCustomEventDamager(); // Paper - fix DamageSource API - if (source.is(DamageTypeTags.IS_EXPLOSION)) { - if (damager == null) { - return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.BLOCK_EXPLOSION, bukkitDamageSource, modifiers, modifierFunctions, cancelled); diff --git a/patches/server/0935-Fix-creation-of-invalid-block-entity-during-world-ge.patch b/patches/server/0935-Fix-creation-of-invalid-block-entity-during-world-ge.patch new file mode 100644 index 0000000000..d12e5cd665 --- /dev/null +++ b/patches/server/0935-Fix-creation-of-invalid-block-entity-during-world-ge.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Pierpaolo Coletta +Date: Sat, 30 Mar 2024 21:06:10 +0100 +Subject: [PATCH] Fix creation of invalid block entity during world generation + + +diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java +index 2e72e92762877b28dd908711671e1dfb933de9b0..b7d29389a357f142237cecd75f8ca91cf1eb6b5b 100644 +--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java ++++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java +@@ -324,7 +324,7 @@ public class WorldGenRegion implements WorldGenLevel { + return false; + } else { + ChunkAccess ichunkaccess = this.getChunk(pos); +- BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false); ++ BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false); final BlockState previousBlockState = iblockdata1; // Paper - Clear block entity before setting up a DUMMY block entity - obfhelper + + if (iblockdata1 != null) { + this.level.onBlockStateChange(pos, iblockdata1, state); +@@ -340,6 +340,17 @@ public class WorldGenRegion implements WorldGenLevel { + ichunkaccess.removeBlockEntity(pos); + } + } else { ++ // Paper start - Clear block entity before setting up a DUMMY block entity ++ // The concept of removing a block entity when the block itself changes is generally lifted ++ // from LevelChunk#setBlockState. ++ // It is however to note that this may only run if the block actually changes. ++ // Otherwise a chest block entity generated by a structure template that is later "updated" to ++ // be waterlogged would remove its existing block entity (see PaperMC/Paper#10750) ++ // This logic is *also* found in LevelChunk#setBlockState. ++ if (previousBlockState != null && !java.util.Objects.equals(previousBlockState.getBlock(), state.getBlock())) { ++ ichunkaccess.removeBlockEntity(pos); ++ } ++ // Paper end - Clear block entity before setting up a DUMMY block entity + CompoundTag nbttagcompound = new CompoundTag(); + + nbttagcompound.putInt("x", pos.getX()); +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +index d4bd4cbc5c4773659662a6d7a09b21a99463c1fb..7a794bb0587ce55b067c67dd17ab5be6a4773030 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -991,9 +991,14 @@ public class LevelChunk extends ChunkAccess { + if (this.blockEntity.getType().isValid(iblockdata)) { + this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), iblockdata, this.blockEntity); + this.loggedInvalidBlockState = false; +- } else if (!this.loggedInvalidBlockState) { +- this.loggedInvalidBlockState = true; +- LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata}); ++ // Paper start - Remove the Block Entity if it's invalid ++ } else { ++ LevelChunk.this.removeBlockEntity(this.getPos()); ++ if (!this.loggedInvalidBlockState) { ++ this.loggedInvalidBlockState = true; ++ LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata}); ++ } ++ // Paper end - Remove the Block Entity if it's invalid + } + + gameprofilerfiller.pop(); diff --git a/patches/server/0936-Fix-creation-of-invalid-block-entity-during-world-ge.patch b/patches/server/0936-Fix-creation-of-invalid-block-entity-during-world-ge.patch deleted file mode 100644 index f476845b96..0000000000 --- a/patches/server/0936-Fix-creation-of-invalid-block-entity-during-world-ge.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Pierpaolo Coletta -Date: Sat, 30 Mar 2024 21:06:10 +0100 -Subject: [PATCH] Fix creation of invalid block entity during world generation - - -diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index 2e72e92762877b28dd908711671e1dfb933de9b0..b7d29389a357f142237cecd75f8ca91cf1eb6b5b 100644 ---- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java -+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -324,7 +324,7 @@ public class WorldGenRegion implements WorldGenLevel { - return false; - } else { - ChunkAccess ichunkaccess = this.getChunk(pos); -- BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false); -+ BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false); final BlockState previousBlockState = iblockdata1; // Paper - Clear block entity before setting up a DUMMY block entity - obfhelper - - if (iblockdata1 != null) { - this.level.onBlockStateChange(pos, iblockdata1, state); -@@ -340,6 +340,17 @@ public class WorldGenRegion implements WorldGenLevel { - ichunkaccess.removeBlockEntity(pos); - } - } else { -+ // Paper start - Clear block entity before setting up a DUMMY block entity -+ // The concept of removing a block entity when the block itself changes is generally lifted -+ // from LevelChunk#setBlockState. -+ // It is however to note that this may only run if the block actually changes. -+ // Otherwise a chest block entity generated by a structure template that is later "updated" to -+ // be waterlogged would remove its existing block entity (see PaperMC/Paper#10750) -+ // This logic is *also* found in LevelChunk#setBlockState. -+ if (previousBlockState != null && !java.util.Objects.equals(previousBlockState.getBlock(), state.getBlock())) { -+ ichunkaccess.removeBlockEntity(pos); -+ } -+ // Paper end - Clear block entity before setting up a DUMMY block entity - CompoundTag nbttagcompound = new CompoundTag(); - - nbttagcompound.putInt("x", pos.getX()); -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 7181acfafad91aa5f6ab7ce663d9be4a1b65b02a..5dd1df0da1f954778aebe0f40611ae0f3a7866ab 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -994,9 +994,14 @@ public class LevelChunk extends ChunkAccess { - if (this.blockEntity.getType().isValid(iblockdata)) { - this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), iblockdata, this.blockEntity); - this.loggedInvalidBlockState = false; -- } else if (!this.loggedInvalidBlockState) { -- this.loggedInvalidBlockState = true; -- LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata}); -+ // Paper start - Remove the Block Entity if it's invalid -+ } else { -+ LevelChunk.this.removeBlockEntity(this.getPos()); -+ if (!this.loggedInvalidBlockState) { -+ this.loggedInvalidBlockState = true; -+ LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata}); -+ } -+ // Paper end - Remove the Block Entity if it's invalid - } - - gameprofilerfiller.pop(); diff --git a/patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch b/patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch new file mode 100644 index 0000000000..7e0fabb39a --- /dev/null +++ b/patches/server/0936-Fix-possible-StackOverflowError-for-some-dispenses.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 29 Oct 2022 17:02:42 -0700 +Subject: [PATCH] Fix possible StackOverflowError for some dispenses + +For saddles, carpets, horse armor, and chests for horse-likes +a BlockDispenseEvent handler that always mutated the item without +changing the type would result in a SO error because when it went +to find the replacement dispense behavior (since the item "changed") +it didn't properly handle if the replacement was the same instance +of dispense behavior. + +Additionally equippable mob heads, wither skulls, and carved pumpkins +are subject to the same possible error. + +diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +index 18304349c9ab24657c4152aff800dba969174665..63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -232,7 +232,7 @@ public interface DispenseItemBehavior { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); + DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); +- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { ++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError + idispensebehavior.dispense(pointer, eventStack); + return stack; + } +@@ -283,7 +283,7 @@ public interface DispenseItemBehavior { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); + DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); +- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { ++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError + idispensebehavior.dispense(pointer, eventStack); + return stack; + } +@@ -645,7 +645,7 @@ public interface DispenseItemBehavior { + stack.shrink(1); + this.setSuccess(true); + } else { +- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack)); ++ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError + } + + return stack; +@@ -691,7 +691,7 @@ public interface DispenseItemBehavior { + stack.shrink(1); + this.setSuccess(true); + } else { +- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack)); ++ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError + } + + return stack; +@@ -819,7 +819,7 @@ public interface DispenseItemBehavior { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); + DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); +- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { ++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError + idispensebehavior.dispense(pointer, eventStack); + return stack; + } +diff --git a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java +index a03cc350973fda213251cad273a2db86f438904b..036dd3b15dfee4cd079710eba1255d2bdb4d7220 100644 +--- a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java +@@ -23,10 +23,15 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { + + @Override + protected ItemStack execute(BlockSource pointer, ItemStack stack) { +- return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack) ? stack : super.execute(pointer, stack); ++ return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, null) ? stack : super.execute(pointer, stack); // Paper - fix possible StackOverflowError + } + +- public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack) { ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper ++ public static boolean dispenseEquipment(BlockSource pointer, ItemStack armor) { ++ // Paper start ++ return dispenseEquipment(pointer, armor, null); ++ } ++ public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack, @javax.annotation.Nullable DispenseItemBehavior currentBehavior) { + BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); + List list = pointer.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), (entityliving) -> { + return entityliving.canEquipWithDispenser(stack); +@@ -59,7 +64,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); + DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); +- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { ++ if (idispensebehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE)) { // Paper - fix possible StackOverflowError + idispensebehavior.dispense(pointer, eventStack); + return true; + } diff --git a/patches/server/0937-Fix-possible-StackOverflowError-for-some-dispenses.patch b/patches/server/0937-Fix-possible-StackOverflowError-for-some-dispenses.patch deleted file mode 100644 index 7e0fabb39a..0000000000 --- a/patches/server/0937-Fix-possible-StackOverflowError-for-some-dispenses.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 29 Oct 2022 17:02:42 -0700 -Subject: [PATCH] Fix possible StackOverflowError for some dispenses - -For saddles, carpets, horse armor, and chests for horse-likes -a BlockDispenseEvent handler that always mutated the item without -changing the type would result in a SO error because when it went -to find the replacement dispense behavior (since the item "changed") -it didn't properly handle if the replacement was the same instance -of dispense behavior. - -Additionally equippable mob heads, wither skulls, and carved pumpkins -are subject to the same possible error. - -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 18304349c9ab24657c4152aff800dba969174665..63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -232,7 +232,7 @@ public interface DispenseItemBehavior { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); - DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { -+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError - idispensebehavior.dispense(pointer, eventStack); - return stack; - } -@@ -283,7 +283,7 @@ public interface DispenseItemBehavior { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); - DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { -+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError - idispensebehavior.dispense(pointer, eventStack); - return stack; - } -@@ -645,7 +645,7 @@ public interface DispenseItemBehavior { - stack.shrink(1); - this.setSuccess(true); - } else { -- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack)); -+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError - } - - return stack; -@@ -691,7 +691,7 @@ public interface DispenseItemBehavior { - stack.shrink(1); - this.setSuccess(true); - } else { -- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack)); -+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError - } - - return stack; -@@ -819,7 +819,7 @@ public interface DispenseItemBehavior { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); - DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { -+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError - idispensebehavior.dispense(pointer, eventStack); - return stack; - } -diff --git a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java -index a03cc350973fda213251cad273a2db86f438904b..036dd3b15dfee4cd079710eba1255d2bdb4d7220 100644 ---- a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java -@@ -23,10 +23,15 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { - - @Override - protected ItemStack execute(BlockSource pointer, ItemStack stack) { -- return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack) ? stack : super.execute(pointer, stack); -+ return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, null) ? stack : super.execute(pointer, stack); // Paper - fix possible StackOverflowError - } - -- public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack) { -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper -+ public static boolean dispenseEquipment(BlockSource pointer, ItemStack armor) { -+ // Paper start -+ return dispenseEquipment(pointer, armor, null); -+ } -+ public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack, @javax.annotation.Nullable DispenseItemBehavior currentBehavior) { - BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING)); - List list = pointer.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), (entityliving) -> { - return entityliving.canEquipWithDispenser(stack); -@@ -59,7 +64,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); - DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) { -+ if (idispensebehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE)) { // Paper - fix possible StackOverflowError - idispensebehavior.dispense(pointer, eventStack); - return true; - } diff --git a/patches/server/0937-Improve-tag-parser-handling.patch b/patches/server/0937-Improve-tag-parser-handling.patch new file mode 100644 index 0000000000..36bc92d7a0 --- /dev/null +++ b/patches/server/0937-Improve-tag-parser-handling.patch @@ -0,0 +1,285 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Mon, 5 Feb 2024 11:54:04 +0100 +Subject: [PATCH] Improve tag parser handling + + +diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +index 92848b64a78fce7a92e1657c2da6fc5ee53eea44..4b4f812eb13d5f03bcf3f8724d8aa8dbbc724e8b 100644 +--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java ++++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +@@ -304,9 +304,15 @@ public class CommandDispatcher { + } + final CommandContextBuilder context = contextSoFar.copy(); + final StringReader reader = new StringReader(originalReader); ++ boolean stop = false; // Paper - Handle non-recoverable exceptions + try { + try { + child.parse(reader, context); ++ // Paper start - Handle non-recoverable exceptions ++ } catch (final io.papermc.paper.brigadier.TagParseCommandSyntaxException e) { ++ stop = true; ++ throw e; ++ // Paper end - Handle non-recoverable exceptions + } catch (final RuntimeException ex) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().createWithContext(reader, ex.getMessage()); + } +@@ -321,6 +327,7 @@ public class CommandDispatcher { + } + errors.put(child, ex); + reader.setCursor(cursor); ++ if (stop) return new ParseResults<>(contextSoFar, originalReader, errors); // Paper - Handle non-recoverable exceptions + continue; + } + +diff --git a/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java b/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a375ad4ba9db990b24a2b9ff366fcba66b753815 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java +@@ -0,0 +1,15 @@ ++package io.papermc.paper.brigadier; ++ ++import com.mojang.brigadier.LiteralMessage; ++import com.mojang.brigadier.exceptions.CommandSyntaxException; ++import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; ++import net.minecraft.network.chat.Component; ++ ++public final class TagParseCommandSyntaxException extends CommandSyntaxException { ++ ++ private static final SimpleCommandExceptionType EXCEPTION_TYPE = new SimpleCommandExceptionType(new LiteralMessage("Error parsing NBT")); ++ ++ public TagParseCommandSyntaxException(final String message) { ++ super(EXCEPTION_TYPE, Component.literal(message)); ++ } ++} +diff --git a/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java b/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java +index 82ecd9c034a2ee5040b6a66233070ce1cb4e48d2..50e66b10ec3943b9068e546763087161395f673a 100644 +--- a/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java ++++ b/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java +@@ -13,7 +13,7 @@ public record SelectorPattern(String pattern, EntitySelector resolved) { + EntitySelectorParser entitySelectorParser = new EntitySelectorParser(new StringReader(selector), true); + return DataResult.success(new SelectorPattern(selector, entitySelectorParser.parse())); + } catch (CommandSyntaxException var2) { +- return DataResult.error(() -> "Invalid selector component: " + selector + ": " + var2.getMessage()); ++ return DataResult.error(() -> "Invalid selector component"); // Paper - limit selector error message + } + } + +diff --git a/src/main/java/net/minecraft/nbt/TagParser.java b/src/main/java/net/minecraft/nbt/TagParser.java +index da101bca71f4710812621b98f0a0d8cab180346a..3cd112584accb8e8f050ac99738eed11c902e60e 100644 +--- a/src/main/java/net/minecraft/nbt/TagParser.java ++++ b/src/main/java/net/minecraft/nbt/TagParser.java +@@ -49,6 +49,7 @@ public class TagParser { + }, CompoundTag::toString); + public static final Codec LENIENT_CODEC = Codec.withAlternative(AS_CODEC, CompoundTag.CODEC); + private final StringReader reader; ++ private int depth; // Paper + + public static CompoundTag parseTag(String string) throws CommandSyntaxException { + return new TagParser(new StringReader(string)).readSingleStruct(); +@@ -159,6 +160,7 @@ public class TagParser { + + public CompoundTag readStruct() throws CommandSyntaxException { + this.expect('{'); ++ this.increaseDepth(); // Paper + CompoundTag compoundTag = new CompoundTag(); + this.reader.skipWhitespace(); + +@@ -182,6 +184,7 @@ public class TagParser { + } + + this.expect('}'); ++ this.depth--; // Paper + return compoundTag; + } + +@@ -191,6 +194,7 @@ public class TagParser { + if (!this.reader.canRead()) { + throw ERROR_EXPECTED_VALUE.createWithContext(this.reader); + } else { ++ this.increaseDepth(); // Paper + ListTag listTag = new ListTag(); + TagType tagType = null; + +@@ -216,6 +220,7 @@ public class TagParser { + } + + this.expect(']'); ++ this.depth--; // Paper + return listTag; + } + } +@@ -288,4 +293,11 @@ public class TagParser { + this.reader.skipWhitespace(); + this.reader.expect(c); + } ++ ++ private void increaseDepth() throws CommandSyntaxException { ++ this.depth++; ++ if (this.depth > 512) { ++ throw new io.papermc.paper.brigadier.TagParseCommandSyntaxException("NBT tag is too complex, depth > 512"); ++ } ++ } + } +diff --git a/src/main/java/net/minecraft/network/chat/ComponentUtils.java b/src/main/java/net/minecraft/network/chat/ComponentUtils.java +index 3365aed2b67ae0e4dd0410f5190ba474f146139b..8b776434a733b91129b089d702b2583b727bf3d2 100644 +--- a/src/main/java/net/minecraft/network/chat/ComponentUtils.java ++++ b/src/main/java/net/minecraft/network/chat/ComponentUtils.java +@@ -33,10 +33,30 @@ public class ComponentUtils { + } + } + ++ @io.papermc.paper.annotation.DoNotUse // Paper - validate separators - right now this method is only used for separator evaluation. Error on build if this changes to re-evaluate. + public static Optional updateForEntity(@Nullable CommandSourceStack source, Optional text, @Nullable Entity sender, int depth) throws CommandSyntaxException { + return text.isPresent() ? Optional.of(updateForEntity(source, text.get(), sender, depth)) : Optional.empty(); + } + ++ // Paper start - validate separator ++ public static Optional updateSeparatorForEntity(@Nullable CommandSourceStack source, Optional text, @Nullable Entity sender, int depth) throws CommandSyntaxException { ++ if (text.isEmpty() || !isValidSelector(text.get())) return Optional.empty(); ++ return Optional.of(updateForEntity(source, text.get(), sender, depth)); ++ } ++ public static boolean isValidSelector(final Component component) { ++ final ComponentContents contents = component.getContents(); ++ ++ if (contents instanceof net.minecraft.network.chat.contents.NbtContents || contents instanceof net.minecraft.network.chat.contents.SelectorContents) return false; ++ if (contents instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents) { ++ for (final Object arg : translatableContents.getArgs()) { ++ if (arg instanceof final Component argumentAsComponent && !isValidSelector(argumentAsComponent)) return false; ++ } ++ } ++ ++ return true; ++ } ++ // Paper end - validate separator ++ + public static MutableComponent updateForEntity(@Nullable CommandSourceStack source, Component text, @Nullable Entity sender, int depth) throws CommandSyntaxException { + if (depth > 100) { + return text.copy(); +diff --git a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java +index df26c39a2bb20e2021b50211dce905483a77f4e6..5634122dac8afeecab0cde623e9868d8e865e02a 100644 +--- a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java ++++ b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java +@@ -120,7 +120,7 @@ public class NbtContents implements ComponentContents { + }).map(Tag::getAsString); + if (this.interpreting) { + Component component = DataFixUtils.orElse( +- ComponentUtils.updateForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR ++ ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR // Paper - validate separator + ); + return stream.flatMap(text -> { + try { +@@ -132,7 +132,7 @@ public class NbtContents implements ComponentContents { + } + }).reduce((accumulator, current) -> accumulator.append(component).append(current)).orElseGet(Component::empty); + } else { +- return ComponentUtils.updateForEntity(source, this.separator, sender, depth) ++ return ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth) // Paper - validate separator + .map( + text -> stream.map(Component::literal) + .reduce((accumulator, current) -> accumulator.append(text).append(current)) +diff --git a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java +index 5e87f5a2bbffe2eba3fc4fb0da51acee99e72fc2..4131067620f723be28a6cdb7508e14d7e2aed48b 100644 +--- a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java ++++ b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java +@@ -36,7 +36,7 @@ public record SelectorContents(SelectorPattern selector, Optional sep + if (source == null) { + return Component.empty(); + } else { +- Optional optional = ComponentUtils.updateForEntity(source, this.separator, sender, depth); ++ Optional optional = ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth); // Paper - validate separator + return ComponentUtils.formatList(this.selector.resolved().findEntities(source), optional, Entity::getDisplayName); + } + } +diff --git a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java +index 56e641bc5f6edc657647993ea2efbb7bb9c2f732..4aa6232bf0f72fcde32d257100bd15b1c5192aaa 100644 +--- a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java ++++ b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java +@@ -181,6 +181,15 @@ public class TranslatableContents implements ComponentContents { + + @Override + public Optional visit(FormattedText.ContentConsumer visitor) { ++ // Paper start - Count visited parts ++ try { ++ return this.visit(new TranslatableContentConsumer<>(visitor)); ++ } catch (IllegalArgumentException ignored) { ++ return visitor.accept("..."); ++ } ++ } ++ private Optional visit(TranslatableContentConsumer visitor) { ++ // Paper end - Count visited parts + this.decompose(); + + for (FormattedText formattedText : this.decomposedParts) { +@@ -192,6 +201,25 @@ public class TranslatableContents implements ComponentContents { + + return Optional.empty(); + } ++ // Paper start - Count visited parts ++ private static final class TranslatableContentConsumer implements FormattedText.ContentConsumer { ++ private static final IllegalArgumentException EX = new IllegalArgumentException("Too long"); ++ private final FormattedText.ContentConsumer visitor; ++ private int visited; ++ ++ private TranslatableContentConsumer(FormattedText.ContentConsumer visitor) { ++ this.visitor = visitor; ++ } ++ ++ @Override ++ public Optional accept(final String asString) { ++ if (visited++ > 32) { ++ throw EX; ++ } ++ return this.visitor.accept(asString); ++ } ++ } ++ // Paper end - Count visited parts + + @Override + public MutableComponent resolve(@Nullable CommandSourceStack source, @Nullable Entity sender, int depth) throws CommandSyntaxException { +diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java +index 898b19887ed34c87003fc63cb5905df2ba6234a5..b47eeb23055b135d5567552ba983bfbc3e1fab67 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java +@@ -19,7 +19,7 @@ public class ServerboundCommandSuggestionPacket implements Packet 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) { ++ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); ++ return; ++ } ++ // Paper end + // Paper start - AsyncTabCompleteEvent + TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet)); + } +@@ -830,6 +837,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader stringreader) { + // Paper end - AsyncTabCompleteEvent + ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); ++ // Paper start - Handle non-recoverable exceptions ++ if (!parseresults.getExceptions().isEmpty() ++ && parseresults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) { ++ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); ++ return; ++ } ++ // Paper end - Handle non-recoverable exceptions + + this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { + // Paper start - Don't tab-complete namespaced commands if send-namespaced is false diff --git a/patches/server/0938-Improve-tag-parser-handling.patch b/patches/server/0938-Improve-tag-parser-handling.patch deleted file mode 100644 index c7b698366d..0000000000 --- a/patches/server/0938-Improve-tag-parser-handling.patch +++ /dev/null @@ -1,285 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Mon, 5 Feb 2024 11:54:04 +0100 -Subject: [PATCH] Improve tag parser handling - - -diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java -index 92848b64a78fce7a92e1657c2da6fc5ee53eea44..4b4f812eb13d5f03bcf3f8724d8aa8dbbc724e8b 100644 ---- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java -+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java -@@ -304,9 +304,15 @@ public class CommandDispatcher { - } - final CommandContextBuilder context = contextSoFar.copy(); - final StringReader reader = new StringReader(originalReader); -+ boolean stop = false; // Paper - Handle non-recoverable exceptions - try { - try { - child.parse(reader, context); -+ // Paper start - Handle non-recoverable exceptions -+ } catch (final io.papermc.paper.brigadier.TagParseCommandSyntaxException e) { -+ stop = true; -+ throw e; -+ // Paper end - Handle non-recoverable exceptions - } catch (final RuntimeException ex) { - throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().createWithContext(reader, ex.getMessage()); - } -@@ -321,6 +327,7 @@ public class CommandDispatcher { - } - errors.put(child, ex); - reader.setCursor(cursor); -+ if (stop) return new ParseResults<>(contextSoFar, originalReader, errors); // Paper - Handle non-recoverable exceptions - continue; - } - -diff --git a/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java b/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a375ad4ba9db990b24a2b9ff366fcba66b753815 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java -@@ -0,0 +1,15 @@ -+package io.papermc.paper.brigadier; -+ -+import com.mojang.brigadier.LiteralMessage; -+import com.mojang.brigadier.exceptions.CommandSyntaxException; -+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -+import net.minecraft.network.chat.Component; -+ -+public final class TagParseCommandSyntaxException extends CommandSyntaxException { -+ -+ private static final SimpleCommandExceptionType EXCEPTION_TYPE = new SimpleCommandExceptionType(new LiteralMessage("Error parsing NBT")); -+ -+ public TagParseCommandSyntaxException(final String message) { -+ super(EXCEPTION_TYPE, Component.literal(message)); -+ } -+} -diff --git a/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java b/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java -index 82ecd9c034a2ee5040b6a66233070ce1cb4e48d2..50e66b10ec3943b9068e546763087161395f673a 100644 ---- a/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java -+++ b/src/main/java/net/minecraft/commands/arguments/selector/SelectorPattern.java -@@ -13,7 +13,7 @@ public record SelectorPattern(String pattern, EntitySelector resolved) { - EntitySelectorParser entitySelectorParser = new EntitySelectorParser(new StringReader(selector), true); - return DataResult.success(new SelectorPattern(selector, entitySelectorParser.parse())); - } catch (CommandSyntaxException var2) { -- return DataResult.error(() -> "Invalid selector component: " + selector + ": " + var2.getMessage()); -+ return DataResult.error(() -> "Invalid selector component"); // Paper - limit selector error message - } - } - -diff --git a/src/main/java/net/minecraft/nbt/TagParser.java b/src/main/java/net/minecraft/nbt/TagParser.java -index da101bca71f4710812621b98f0a0d8cab180346a..3cd112584accb8e8f050ac99738eed11c902e60e 100644 ---- a/src/main/java/net/minecraft/nbt/TagParser.java -+++ b/src/main/java/net/minecraft/nbt/TagParser.java -@@ -49,6 +49,7 @@ public class TagParser { - }, CompoundTag::toString); - public static final Codec LENIENT_CODEC = Codec.withAlternative(AS_CODEC, CompoundTag.CODEC); - private final StringReader reader; -+ private int depth; // Paper - - public static CompoundTag parseTag(String string) throws CommandSyntaxException { - return new TagParser(new StringReader(string)).readSingleStruct(); -@@ -159,6 +160,7 @@ public class TagParser { - - public CompoundTag readStruct() throws CommandSyntaxException { - this.expect('{'); -+ this.increaseDepth(); // Paper - CompoundTag compoundTag = new CompoundTag(); - this.reader.skipWhitespace(); - -@@ -182,6 +184,7 @@ public class TagParser { - } - - this.expect('}'); -+ this.depth--; // Paper - return compoundTag; - } - -@@ -191,6 +194,7 @@ public class TagParser { - if (!this.reader.canRead()) { - throw ERROR_EXPECTED_VALUE.createWithContext(this.reader); - } else { -+ this.increaseDepth(); // Paper - ListTag listTag = new ListTag(); - TagType tagType = null; - -@@ -216,6 +220,7 @@ public class TagParser { - } - - this.expect(']'); -+ this.depth--; // Paper - return listTag; - } - } -@@ -288,4 +293,11 @@ public class TagParser { - this.reader.skipWhitespace(); - this.reader.expect(c); - } -+ -+ private void increaseDepth() throws CommandSyntaxException { -+ this.depth++; -+ if (this.depth > 512) { -+ throw new io.papermc.paper.brigadier.TagParseCommandSyntaxException("NBT tag is too complex, depth > 512"); -+ } -+ } - } -diff --git a/src/main/java/net/minecraft/network/chat/ComponentUtils.java b/src/main/java/net/minecraft/network/chat/ComponentUtils.java -index 3365aed2b67ae0e4dd0410f5190ba474f146139b..8b776434a733b91129b089d702b2583b727bf3d2 100644 ---- a/src/main/java/net/minecraft/network/chat/ComponentUtils.java -+++ b/src/main/java/net/minecraft/network/chat/ComponentUtils.java -@@ -33,10 +33,30 @@ public class ComponentUtils { - } - } - -+ @io.papermc.paper.annotation.DoNotUse // Paper - validate separators - right now this method is only used for separator evaluation. Error on build if this changes to re-evaluate. - public static Optional updateForEntity(@Nullable CommandSourceStack source, Optional text, @Nullable Entity sender, int depth) throws CommandSyntaxException { - return text.isPresent() ? Optional.of(updateForEntity(source, text.get(), sender, depth)) : Optional.empty(); - } - -+ // Paper start - validate separator -+ public static Optional updateSeparatorForEntity(@Nullable CommandSourceStack source, Optional text, @Nullable Entity sender, int depth) throws CommandSyntaxException { -+ if (text.isEmpty() || !isValidSelector(text.get())) return Optional.empty(); -+ return Optional.of(updateForEntity(source, text.get(), sender, depth)); -+ } -+ public static boolean isValidSelector(final Component component) { -+ final ComponentContents contents = component.getContents(); -+ -+ if (contents instanceof net.minecraft.network.chat.contents.NbtContents || contents instanceof net.minecraft.network.chat.contents.SelectorContents) return false; -+ if (contents instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents) { -+ for (final Object arg : translatableContents.getArgs()) { -+ if (arg instanceof final Component argumentAsComponent && !isValidSelector(argumentAsComponent)) return false; -+ } -+ } -+ -+ return true; -+ } -+ // Paper end - validate separator -+ - public static MutableComponent updateForEntity(@Nullable CommandSourceStack source, Component text, @Nullable Entity sender, int depth) throws CommandSyntaxException { - if (depth > 100) { - return text.copy(); -diff --git a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java -index df26c39a2bb20e2021b50211dce905483a77f4e6..5634122dac8afeecab0cde623e9868d8e865e02a 100644 ---- a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java -+++ b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java -@@ -120,7 +120,7 @@ public class NbtContents implements ComponentContents { - }).map(Tag::getAsString); - if (this.interpreting) { - Component component = DataFixUtils.orElse( -- ComponentUtils.updateForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR -+ ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR // Paper - validate separator - ); - return stream.flatMap(text -> { - try { -@@ -132,7 +132,7 @@ public class NbtContents implements ComponentContents { - } - }).reduce((accumulator, current) -> accumulator.append(component).append(current)).orElseGet(Component::empty); - } else { -- return ComponentUtils.updateForEntity(source, this.separator, sender, depth) -+ return ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth) // Paper - validate separator - .map( - text -> stream.map(Component::literal) - .reduce((accumulator, current) -> accumulator.append(text).append(current)) -diff --git a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java -index 5e87f5a2bbffe2eba3fc4fb0da51acee99e72fc2..4131067620f723be28a6cdb7508e14d7e2aed48b 100644 ---- a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java -+++ b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java -@@ -36,7 +36,7 @@ public record SelectorContents(SelectorPattern selector, Optional sep - if (source == null) { - return Component.empty(); - } else { -- Optional optional = ComponentUtils.updateForEntity(source, this.separator, sender, depth); -+ Optional optional = ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth); // Paper - validate separator - return ComponentUtils.formatList(this.selector.resolved().findEntities(source), optional, Entity::getDisplayName); - } - } -diff --git a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java -index 56e641bc5f6edc657647993ea2efbb7bb9c2f732..4aa6232bf0f72fcde32d257100bd15b1c5192aaa 100644 ---- a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java -+++ b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java -@@ -181,6 +181,15 @@ public class TranslatableContents implements ComponentContents { - - @Override - public Optional visit(FormattedText.ContentConsumer visitor) { -+ // Paper start - Count visited parts -+ try { -+ return this.visit(new TranslatableContentConsumer<>(visitor)); -+ } catch (IllegalArgumentException ignored) { -+ return visitor.accept("..."); -+ } -+ } -+ private Optional visit(TranslatableContentConsumer visitor) { -+ // Paper end - Count visited parts - this.decompose(); - - for (FormattedText formattedText : this.decomposedParts) { -@@ -192,6 +201,25 @@ public class TranslatableContents implements ComponentContents { - - return Optional.empty(); - } -+ // Paper start - Count visited parts -+ private static final class TranslatableContentConsumer implements FormattedText.ContentConsumer { -+ private static final IllegalArgumentException EX = new IllegalArgumentException("Too long"); -+ private final FormattedText.ContentConsumer visitor; -+ private int visited; -+ -+ private TranslatableContentConsumer(FormattedText.ContentConsumer visitor) { -+ this.visitor = visitor; -+ } -+ -+ @Override -+ public Optional accept(final String asString) { -+ if (visited++ > 32) { -+ throw EX; -+ } -+ return this.visitor.accept(asString); -+ } -+ } -+ // Paper end - Count visited parts - - @Override - public MutableComponent resolve(@Nullable CommandSourceStack source, @Nullable Entity sender, int depth) throws CommandSyntaxException { -diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java -index 898b19887ed34c87003fc63cb5905df2ba6234a5..b47eeb23055b135d5567552ba983bfbc3e1fab67 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java -@@ -19,7 +19,7 @@ public class ServerboundCommandSuggestionPacket implements Packet 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) { -+ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); -+ return; -+ } -+ // Paper end - // Paper start - AsyncTabCompleteEvent - TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet)); - } -@@ -830,6 +837,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader stringreader) { - // Paper end - AsyncTabCompleteEvent - ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); -+ // Paper start - Handle non-recoverable exceptions -+ if (!parseresults.getExceptions().isEmpty() -+ && parseresults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) { -+ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); -+ return; -+ } -+ // Paper end - Handle non-recoverable exceptions - - this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { - // Paper start - Don't tab-complete namespaced commands if send-namespaced is false diff --git a/patches/server/0938-Item-Mutation-Fixes.patch b/patches/server/0938-Item-Mutation-Fixes.patch new file mode 100644 index 0000000000..f7242e591f --- /dev/null +++ b/patches/server/0938-Item-Mutation-Fixes.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 20 Mar 2024 20:41:35 -0400 +Subject: [PATCH] Item Mutation Fixes + + +diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +index 36496144dd6fa87163b692034570eba70c83678c..b7300052f3c3d496ea41b681a2d5d5b554e67c63 100644 +--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +@@ -220,7 +220,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { + return false; + } else if (this.costs[id] > 0 && !itemstack.isEmpty() && (player.experienceLevel >= j && player.experienceLevel >= this.costs[id] || player.getAbilities().instabuild)) { + this.access.execute((world, blockposition) -> { +- ItemStack itemstack2 = itemstack; ++ ItemStack itemstack2 = itemstack; // Paper - diff on change + List list = this.getEnchantmentList(world.registryAccess(), itemstack, id, this.costs[id]); + + // CraftBukkit start +@@ -243,10 +243,16 @@ public class EnchantmentMenu extends AbstractContainerMenu { + return; + } + // CraftBukkit end +- if (itemstack.is(Items.BOOK)) { +- itemstack2 = itemstack.transmuteCopy(Items.ENCHANTED_BOOK); ++ // Paper start ++ itemstack2 = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(item, event.getItem()); ++ if (itemstack2 != itemstack) { + this.enchantSlots.setItem(0, itemstack2); + } ++ if (itemstack2.is(Items.BOOK)) { ++ itemstack2 = itemstack2.transmuteCopy(Items.ENCHANTED_BOOK); ++ this.enchantSlots.setItem(0, itemstack2); ++ } ++ // Paper end + + // CraftBukkit start + for (Map.Entry entry : event.getEnchantsToAdd().entrySet()) { diff --git a/patches/server/0939-Item-Mutation-Fixes.patch b/patches/server/0939-Item-Mutation-Fixes.patch deleted file mode 100644 index f7242e591f..0000000000 --- a/patches/server/0939-Item-Mutation-Fixes.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 20 Mar 2024 20:41:35 -0400 -Subject: [PATCH] Item Mutation Fixes - - -diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -index 36496144dd6fa87163b692034570eba70c83678c..b7300052f3c3d496ea41b681a2d5d5b554e67c63 100644 ---- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -220,7 +220,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { - return false; - } else if (this.costs[id] > 0 && !itemstack.isEmpty() && (player.experienceLevel >= j && player.experienceLevel >= this.costs[id] || player.getAbilities().instabuild)) { - this.access.execute((world, blockposition) -> { -- ItemStack itemstack2 = itemstack; -+ ItemStack itemstack2 = itemstack; // Paper - diff on change - List list = this.getEnchantmentList(world.registryAccess(), itemstack, id, this.costs[id]); - - // CraftBukkit start -@@ -243,10 +243,16 @@ public class EnchantmentMenu extends AbstractContainerMenu { - return; - } - // CraftBukkit end -- if (itemstack.is(Items.BOOK)) { -- itemstack2 = itemstack.transmuteCopy(Items.ENCHANTED_BOOK); -+ // Paper start -+ itemstack2 = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(item, event.getItem()); -+ if (itemstack2 != itemstack) { - this.enchantSlots.setItem(0, itemstack2); - } -+ if (itemstack2.is(Items.BOOK)) { -+ itemstack2 = itemstack2.transmuteCopy(Items.ENCHANTED_BOOK); -+ this.enchantSlots.setItem(0, itemstack2); -+ } -+ // Paper end - - // CraftBukkit start - for (Map.Entry entry : event.getEnchantsToAdd().entrySet()) { diff --git a/patches/server/0939-Per-world-ticks-per-spawn-settings.patch b/patches/server/0939-Per-world-ticks-per-spawn-settings.patch new file mode 100644 index 0000000000..2746e3483b --- /dev/null +++ b/patches/server/0939-Per-world-ticks-per-spawn-settings.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 13 Nov 2021 12:36:26 -0800 +Subject: [PATCH] Per world ticks per spawn settings + + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 01fbefdbed48ab85481c811cca532c91860626f7..083b72ebacfbba22af2230fb69b311aeee62cb6a 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -185,6 +185,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + return this.getChunkIfLoaded(chunkX, chunkZ) != null; + } + // Paper end - Use getChunkIfLoadedImmediately ++ // Paper start - per world ticks per spawn ++ private int getTicksPerSpawn(SpawnCategory spawnCategory) { ++ final int perWorld = this.paperConfig().entities.spawning.ticksPerSpawn.getInt(CraftSpawnCategory.toNMS(spawnCategory)); ++ if (perWorld >= 0) { ++ return perWorld; ++ } ++ return this.getCraftServer().getTicksPerSpawns(spawnCategory); ++ } ++ // Paper end + + + public abstract ResourceKey getTypeKey(); +@@ -198,7 +207,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + // CraftBukkit Ticks things + for (SpawnCategory spawnCategory : SpawnCategory.values()) { + if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { +- this.ticksPerSpawnCategory.put(spawnCategory, (long) this.getCraftServer().getTicksPerSpawns(spawnCategory)); ++ this.ticksPerSpawnCategory.put(spawnCategory, this.getTicksPerSpawn(spawnCategory)); // Paper + } + } + diff --git a/patches/server/0940-Per-world-ticks-per-spawn-settings.patch b/patches/server/0940-Per-world-ticks-per-spawn-settings.patch deleted file mode 100644 index a028a8c234..0000000000 --- a/patches/server/0940-Per-world-ticks-per-spawn-settings.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 13 Nov 2021 12:36:26 -0800 -Subject: [PATCH] Per world ticks per spawn settings - - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 83537aa240ebff8dd19b450956730dc3d4f355a0..ffe894f3034a967f7e3d820c6416acb8adbcfb84 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -186,6 +186,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - return this.getChunkIfLoaded(chunkX, chunkZ) != null; - } - // Paper end - Use getChunkIfLoadedImmediately -+ // Paper start - per world ticks per spawn -+ private int getTicksPerSpawn(SpawnCategory spawnCategory) { -+ final int perWorld = this.paperConfig().entities.spawning.ticksPerSpawn.getInt(CraftSpawnCategory.toNMS(spawnCategory)); -+ if (perWorld >= 0) { -+ return perWorld; -+ } -+ return this.getCraftServer().getTicksPerSpawns(spawnCategory); -+ } -+ // Paper end - - - public abstract ResourceKey getTypeKey(); -@@ -199,7 +208,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // CraftBukkit Ticks things - for (SpawnCategory spawnCategory : SpawnCategory.values()) { - if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { -- this.ticksPerSpawnCategory.put(spawnCategory, (long) this.getCraftServer().getTicksPerSpawns(spawnCategory)); -+ this.ticksPerSpawnCategory.put(spawnCategory, this.getTicksPerSpawn(spawnCategory)); // Paper - } - } - diff --git a/patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch b/patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch new file mode 100644 index 0000000000..3885b9f8a2 --- /dev/null +++ b/patches/server/0940-Properly-track-the-changed-item-from-dispense-events.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 12 Dec 2022 12:14:03 -0800 +Subject: [PATCH] Properly track the changed item from dispense events + + +diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +index 63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1..cd77e86ff289634d2dd1c56002e569ff70d15f25 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -129,10 +129,14 @@ public interface DispenseItemBehavior { + idispensebehavior.dispense(pointer, eventStack); + return stack; + } ++ // Paper start - track changed items in the dispense event ++ itemstack1 = CraftItemStack.unwrap(event.getItem()); // unwrap is safe because the stack won't be modified ++ entitytypes = ((SpawnEggItem) itemstack1.getItem()).getType(itemstack1); ++ // Paper end - track changed item from dispense event + } + + try { +- entitytypes.spawn(pointer.level(), stack, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); ++ entitytypes.spawn(pointer.level(), itemstack1, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); // Paper - track changed item in dispense event + } catch (Exception exception) { + DispenseItemBehavior.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), exception); // CraftBukkit - decompile error + return ItemStack.EMPTY; +@@ -186,9 +190,10 @@ public interface DispenseItemBehavior { + } + // CraftBukkit end + ++ final ItemStack newStack = CraftItemStack.unwrap(event.getItem()); // Paper - use event itemstack (unwrap is fine here because the stack won't be modified) + Consumer consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> { + entityarmorstand.setYRot(enumdirection.toYRot()); +- }, worldserver, stack, (Player) null); ++ }, worldserver, newStack, (Player) null); // Paper - track changed items in the dispense event + ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, consumer, blockposition, EntitySpawnReason.DISPENSER, false, false); + + if (entityarmorstand != null) { +@@ -237,7 +242,7 @@ public interface DispenseItemBehavior { + return stack; + } + } +- ((Saddleable) list.get(0)).equipSaddle(itemstack1, SoundSource.BLOCKS); ++ ((Saddleable) list.get(0)).equipSaddle(CraftItemStack.asNMSCopy(event.getItem()), SoundSource.BLOCKS); // Paper - track changed items in dispense event + // CraftBukkit end + this.setSuccess(true); + return stack; +@@ -330,6 +335,7 @@ public interface DispenseItemBehavior { + int y = blockposition.getY(); + int z = blockposition.getZ(); + BlockState iblockdata = worldserver.getBlockState(blockposition); ++ ItemStack dispensedItem = stack; // Paper - track changed item from the dispense event + // Paper start - correctly check if the bucket place will succeed + /* Taken from SolidBucketItem#emptyContents */ + boolean willEmptyContentsSolidBucketItem = dispensiblecontaineritem instanceof net.minecraft.world.item.SolidBucketItem && worldserver.isInWorldBounds(blockposition) && iblockdata.isAir(); +@@ -359,12 +365,15 @@ public interface DispenseItemBehavior { + } + } + +- dispensiblecontaineritem = (DispensibleContainerItem) CraftItemStack.asNMSCopy(event.getItem()).getItem(); ++ // Paper start - track changed item from dispense event ++ dispensedItem = CraftItemStack.unwrap(event.getItem()); // unwrap is safe here as the stack isn't mutated ++ dispensiblecontaineritem = (DispensibleContainerItem) dispensedItem.getItem(); ++ // Paper end - track changed item from dispense event + } + // CraftBukkit end + + if (dispensiblecontaineritem.emptyContents((Player) null, worldserver, blockposition, (BlockHitResult) null)) { +- dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, stack, blockposition); ++ dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, dispensedItem, blockposition); // Paper - track changed item from dispense event + return this.consumeWithRemainder(pointer, stack, new ItemStack(Items.BUCKET)); + } else { + return this.defaultDispenseItemBehavior.dispense(pointer, stack); +diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +index a9d230d6ff22d5e3a11b2f31e7d751f44888a12c..af222679d0d44d24b2b10455eb52fa8a797ca28a 100644 +--- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +@@ -64,7 +64,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { + } + } + +- Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, stack, enumdirection), worldserver, stack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); ++ Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, CraftItemStack.unwrap(event.getItem()), enumdirection), worldserver, stack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies + ((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity()); + // itemstack.shrink(1); // CraftBukkit - Handled during event processing + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +index f84987c36a16df19286d6f1badfb1ffb9cc7e770..8e089f7d5e7fa9ddeccd0691185555f279d55426 100644 +--- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +@@ -57,7 +57,12 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { + // CraftBukkit end + + try { +- this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, stack, enumdirection1)).consumesAction()); ++ // Paper start - track changed items in the dispense event ++ this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, CraftItemStack.asNMSCopy(event.getItem()), enumdirection1)).consumesAction()); ++ if (this.isSuccess()) { ++ stack.shrink(1); // vanilla shrink is in the place function above, manually handle it here ++ } ++ // Paper end - track changed items in the dispense event + } catch (Exception exception) { + ShulkerBoxDispenseBehavior.LOGGER.error("Error trying to place shulker box at {}", blockposition, exception); + } diff --git a/patches/server/0941-Properly-track-the-changed-item-from-dispense-events.patch b/patches/server/0941-Properly-track-the-changed-item-from-dispense-events.patch deleted file mode 100644 index 3885b9f8a2..0000000000 --- a/patches/server/0941-Properly-track-the-changed-item-from-dispense-events.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 12 Dec 2022 12:14:03 -0800 -Subject: [PATCH] Properly track the changed item from dispense events - - -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1..cd77e86ff289634d2dd1c56002e569ff70d15f25 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -129,10 +129,14 @@ public interface DispenseItemBehavior { - idispensebehavior.dispense(pointer, eventStack); - return stack; - } -+ // Paper start - track changed items in the dispense event -+ itemstack1 = CraftItemStack.unwrap(event.getItem()); // unwrap is safe because the stack won't be modified -+ entitytypes = ((SpawnEggItem) itemstack1.getItem()).getType(itemstack1); -+ // Paper end - track changed item from dispense event - } - - try { -- entitytypes.spawn(pointer.level(), stack, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); -+ entitytypes.spawn(pointer.level(), itemstack1, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); // Paper - track changed item in dispense event - } catch (Exception exception) { - DispenseItemBehavior.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), exception); // CraftBukkit - decompile error - return ItemStack.EMPTY; -@@ -186,9 +190,10 @@ public interface DispenseItemBehavior { - } - // CraftBukkit end - -+ final ItemStack newStack = CraftItemStack.unwrap(event.getItem()); // Paper - use event itemstack (unwrap is fine here because the stack won't be modified) - Consumer consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> { - entityarmorstand.setYRot(enumdirection.toYRot()); -- }, worldserver, stack, (Player) null); -+ }, worldserver, newStack, (Player) null); // Paper - track changed items in the dispense event - ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, consumer, blockposition, EntitySpawnReason.DISPENSER, false, false); - - if (entityarmorstand != null) { -@@ -237,7 +242,7 @@ public interface DispenseItemBehavior { - return stack; - } - } -- ((Saddleable) list.get(0)).equipSaddle(itemstack1, SoundSource.BLOCKS); -+ ((Saddleable) list.get(0)).equipSaddle(CraftItemStack.asNMSCopy(event.getItem()), SoundSource.BLOCKS); // Paper - track changed items in dispense event - // CraftBukkit end - this.setSuccess(true); - return stack; -@@ -330,6 +335,7 @@ public interface DispenseItemBehavior { - int y = blockposition.getY(); - int z = blockposition.getZ(); - BlockState iblockdata = worldserver.getBlockState(blockposition); -+ ItemStack dispensedItem = stack; // Paper - track changed item from the dispense event - // Paper start - correctly check if the bucket place will succeed - /* Taken from SolidBucketItem#emptyContents */ - boolean willEmptyContentsSolidBucketItem = dispensiblecontaineritem instanceof net.minecraft.world.item.SolidBucketItem && worldserver.isInWorldBounds(blockposition) && iblockdata.isAir(); -@@ -359,12 +365,15 @@ public interface DispenseItemBehavior { - } - } - -- dispensiblecontaineritem = (DispensibleContainerItem) CraftItemStack.asNMSCopy(event.getItem()).getItem(); -+ // Paper start - track changed item from dispense event -+ dispensedItem = CraftItemStack.unwrap(event.getItem()); // unwrap is safe here as the stack isn't mutated -+ dispensiblecontaineritem = (DispensibleContainerItem) dispensedItem.getItem(); -+ // Paper end - track changed item from dispense event - } - // CraftBukkit end - - if (dispensiblecontaineritem.emptyContents((Player) null, worldserver, blockposition, (BlockHitResult) null)) { -- dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, stack, blockposition); -+ dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, dispensedItem, blockposition); // Paper - track changed item from dispense event - return this.consumeWithRemainder(pointer, stack, new ItemStack(Items.BUCKET)); - } else { - return this.defaultDispenseItemBehavior.dispense(pointer, stack); -diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -index a9d230d6ff22d5e3a11b2f31e7d751f44888a12c..af222679d0d44d24b2b10455eb52fa8a797ca28a 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -@@ -64,7 +64,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { - } - } - -- Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, stack, enumdirection), worldserver, stack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); -+ Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, CraftItemStack.unwrap(event.getItem()), enumdirection), worldserver, stack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies - ((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity()); - // itemstack.shrink(1); // CraftBukkit - Handled during event processing - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -index f84987c36a16df19286d6f1badfb1ffb9cc7e770..8e089f7d5e7fa9ddeccd0691185555f279d55426 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -@@ -57,7 +57,12 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { - // CraftBukkit end - - try { -- this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, stack, enumdirection1)).consumesAction()); -+ // Paper start - track changed items in the dispense event -+ this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, CraftItemStack.asNMSCopy(event.getItem()), enumdirection1)).consumesAction()); -+ if (this.isSuccess()) { -+ stack.shrink(1); // vanilla shrink is in the place function above, manually handle it here -+ } -+ // Paper end - track changed items in the dispense event - } catch (Exception exception) { - ShulkerBoxDispenseBehavior.LOGGER.error("Error trying to place shulker box at {}", blockposition, exception); - } diff --git a/patches/server/0941-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/0941-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch new file mode 100644 index 0000000000..5c06384279 --- /dev/null +++ b/patches/server/0941-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch @@ -0,0 +1,171 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 13 May 2020 23:01:26 -0400 +Subject: [PATCH] Protect Bedrock and End Portal/Frames from being destroyed + +This fixes exploits that let players destroy bedrock by Pistons, explosions +and Mushrooom/Tree generation. + +These blocks are designed to not be broken except by creative players/commands. +So protect them from a multitude of methods of destroying them. + +A config is provided if you rather let players use these exploits, and let +them destroy the worlds End Portals and get on top of the nether easy. + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 083b72ebacfbba22af2230fb69b311aeee62cb6a..ba4006bc7dc31d10f37023cba7995a9621796f73 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -445,6 +445,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { + // CraftBukkit start - tree generation + if (this.captureTreeGeneration) { ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed ++ BlockState type = getBlockState(pos); ++ if (!type.isDestroyable()) return false; ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed + CraftBlockState blockstate = this.capturedBlockStates.get(pos); + if (blockstate == null) { + blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags); +diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java +index 86656de31b1e33381eddd3ef210122118b31e620..fd1ecedfab037e377e4dded61539689bacc90f80 100644 +--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java ++++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java +@@ -150,6 +150,7 @@ public class ServerExplosion implements Explosion { + for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) { + BlockPos blockposition = BlockPos.containing(d4, d5, d6); + BlockState iblockdata = this.level.getBlockState(blockposition); ++ if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed + FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions + + if (!this.level.isInWorldBounds(blockposition)) { +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index dc242451f397ae6a30b830ef1f211f1a066423a4..0f7b73634930df02d7b0a7f44890597cc2e6deca 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -88,6 +88,21 @@ public class Block extends BlockBehaviour implements ItemLike { + public static final int UPDATE_LIMIT = 512; + protected final StateDefinition stateDefinition; + private BlockState defaultBlockState; ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed ++ public final boolean isDestroyable() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || ++ this != Blocks.BARRIER && ++ this != Blocks.BEDROCK && ++ this != Blocks.END_PORTAL_FRAME && ++ this != Blocks.END_PORTAL && ++ this != Blocks.END_GATEWAY && ++ this != Blocks.COMMAND_BLOCK && ++ this != Blocks.REPEATING_COMMAND_BLOCK && ++ this != Blocks.CHAIN_COMMAND_BLOCK && ++ this != Blocks.STRUCTURE_BLOCK && ++ this != Blocks.JIGSAW; ++ } ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed + @Nullable + private Item item; + private static final int CACHE_SIZE = 256; +diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java +index e841fccb8f298ef692677583b468869f56dc722c..4b51472502d08ea357da437afeb4b581979e9cff 100644 +--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java +@@ -216,6 +216,12 @@ public class PistonBaseBlock extends DirectionalBlock { + @Override + protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) { + Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING); ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur) ++ Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) { ++ return false; ++ } ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed + BlockState iblockdata1 = (BlockState) state.setValue(PistonBaseBlock.EXTENDED, true); + + if (!world.isClientSide) { +@@ -256,7 +262,7 @@ public class PistonBaseBlock extends DirectionalBlock { + } + // Paper end - Fix sticky pistons and BlockPistonRetractEvent + world.setBlock(pos, iblockdata2, 20); +- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); ++ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change + world.blockUpdated(pos, iblockdata2.getBlock()); + iblockdata2.updateNeighbourShapes(world, pos, 2); + if (this.isSticky) { +@@ -292,7 +298,14 @@ public class PistonBaseBlock extends DirectionalBlock { + } + } + } else { +- world.removeBlock(pos.relative(enumdirection), false); ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; fix headless pistons breaking blocks ++ BlockPos headPos = pos.relative(enumdirection); ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston. ++ world.removeBlock(headPos, false); ++ } else { ++ ((ServerLevel) world).getChunkSource().blockChanged(headPos); // ... fix client desync ++ } ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed + } + + world.playSound((Player) null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F); +diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +index 1b988b92e80faa1ac224caf9f9e955ac43a4c45a..95d30c2db7e291d65c24feb114b0f3598d280912 100644 +--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java ++++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +@@ -178,7 +178,7 @@ public abstract class BlockBehaviour implements FeatureElement { + } + + protected void onExplosionHit(BlockState state, ServerLevel world, BlockPos pos, Explosion explosion, BiConsumer stackMerger) { +- if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK) { ++ if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed + Block block = state.getBlock(); + boolean flag = explosion.getIndirectSourceEntity() instanceof Player; + +@@ -257,7 +257,7 @@ public abstract class BlockBehaviour implements FeatureElement { + } + + protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) { +- return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())); ++ return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed + } + + protected boolean canBeReplaced(BlockState state, Fluid fluid) { +@@ -945,6 +945,12 @@ public abstract class BlockBehaviour implements FeatureElement { + return this.legacySolid; + } + ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed ++ public final boolean isDestroyable() { ++ return getBlock().isDestroyable(); ++ } ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed ++ + public boolean isValidSpawn(BlockGetter world, BlockPos pos, EntityType type) { + return this.getBlock().properties.isValidSpawn.test(this.asState(), world, pos, type); + } +@@ -1048,7 +1054,7 @@ public abstract class BlockBehaviour implements FeatureElement { + } + + public PushReaction getPistonPushReaction() { +- return this.pushReaction; ++ return !this.isDestroyable() ? PushReaction.BLOCK : this.pushReaction; // Paper - Protect Bedrock and End Portal/Frames from being destroyed + } + + public boolean isSolidRender() { +diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java +index eb409fb5e673d2a343813946cc59cb5da2328eec..83d294f6f48b867d09ea0d339c779011bf4138a5 100644 +--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java ++++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java +@@ -207,6 +207,13 @@ public class PortalForcer { + for (int j = -1; j < 3; ++j) { + for (int k = -1; k < 4; ++k) { + temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal); ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { ++ if (!this.level.getBlockState(temp).isDestroyable()) { ++ return false; ++ } ++ } ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed + if (k < 0 && !this.level.getBlockState(temp).isSolid()) { + return false; + } diff --git a/patches/server/0942-Add-config-for-mobs-immune-to-default-effects.patch b/patches/server/0942-Add-config-for-mobs-immune-to-default-effects.patch new file mode 100644 index 0000000000..c3b01a16ed --- /dev/null +++ b/patches/server/0942-Add-config-for-mobs-immune-to-default-effects.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Dec 2020 21:03:02 -0800 +Subject: [PATCH] Add config for mobs immune to default effects + + +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +index e1be143959fbaa1d54af2a1a2c27187d70e6a9e9..244e38db508efa3eebebb6392c4ebb0805367baf 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -602,7 +602,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { + + @Override + public boolean canBeAffected(MobEffectInstance effect) { +- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect); ++ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.wither ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects + } + + private class WitherDoNothingGoal extends Goal { +diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java +index 72e42605c278028480c368762da18f61806d766a..91e521414c3ea5722aac7506b7589fbb399e9636 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Spider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java +@@ -126,7 +126,7 @@ public class Spider extends Monster { + + @Override + public boolean canBeAffected(MobEffectInstance effect) { +- return effect.is(MobEffects.POISON) ? false : super.canBeAffected(effect); ++ return effect.is(MobEffects.POISON) && this.level().paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects + } + + public boolean isClimbing() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java +index c295b604f438c62d589ab05ea44c85dbefcb258b..37d3acda84a984bf4f1c44b3d27e2102839d3e8e 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -114,6 +114,6 @@ public class WitherSkeleton extends AbstractSkeleton { + + @Override + public boolean canBeAffected(MobEffectInstance effect) { +- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect); ++ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects + } + } diff --git a/patches/server/0942-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/0942-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch deleted file mode 100644 index 40895c886c..0000000000 --- a/patches/server/0942-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 13 May 2020 23:01:26 -0400 -Subject: [PATCH] Protect Bedrock and End Portal/Frames from being destroyed - -This fixes exploits that let players destroy bedrock by Pistons, explosions -and Mushrooom/Tree generation. - -These blocks are designed to not be broken except by creative players/commands. -So protect them from a multitude of methods of destroying them. - -A config is provided if you rather let players use these exploits, and let -them destroy the worlds End Portals and get on top of the nether easy. - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index ffe894f3034a967f7e3d820c6416acb8adbcfb84..35b9a6d382e420844fc21c88b7d8044e3b8b8368 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -447,6 +447,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { - // CraftBukkit start - tree generation - if (this.captureTreeGeneration) { -+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed -+ BlockState type = getBlockState(pos); -+ if (!type.isDestroyable()) return false; -+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed - CraftBlockState blockstate = this.capturedBlockStates.get(pos); - if (blockstate == null) { - blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags); -diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java -index 86656de31b1e33381eddd3ef210122118b31e620..fd1ecedfab037e377e4dded61539689bacc90f80 100644 ---- a/src/main/java/net/minecraft/world/level/ServerExplosion.java -+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java -@@ -150,6 +150,7 @@ public class ServerExplosion implements Explosion { - for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) { - BlockPos blockposition = BlockPos.containing(d4, d5, d6); - BlockState iblockdata = this.level.getBlockState(blockposition); -+ if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed - FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions - - if (!this.level.isInWorldBounds(blockposition)) { -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 9917df070d9815b6915e4a0b022dfe4e5b7861e7..729c3d8279b13d21c65ede89ea50869b69d5bfe6 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -89,6 +89,19 @@ public class Block extends BlockBehaviour implements ItemLike { - protected final StateDefinition stateDefinition; - private BlockState defaultBlockState; - // Paper start -+ public final boolean isDestroyable() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || -+ this != Blocks.BARRIER && -+ this != Blocks.BEDROCK && -+ this != Blocks.END_PORTAL_FRAME && -+ this != Blocks.END_PORTAL && -+ this != Blocks.END_GATEWAY && -+ this != Blocks.COMMAND_BLOCK && -+ this != Blocks.REPEATING_COMMAND_BLOCK && -+ this != Blocks.CHAIN_COMMAND_BLOCK && -+ this != Blocks.STRUCTURE_BLOCK && -+ this != Blocks.JIGSAW; -+ } - public co.aikar.timings.Timing timing; - public co.aikar.timings.Timing getTiming() { - if (timing == null) { -diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -index e841fccb8f298ef692677583b468869f56dc722c..4b51472502d08ea357da437afeb4b581979e9cff 100644 ---- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -@@ -216,6 +216,12 @@ public class PistonBaseBlock extends DirectionalBlock { - @Override - protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) { - Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING); -+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur) -+ Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) { -+ return false; -+ } -+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed - BlockState iblockdata1 = (BlockState) state.setValue(PistonBaseBlock.EXTENDED, true); - - if (!world.isClientSide) { -@@ -256,7 +262,7 @@ public class PistonBaseBlock extends DirectionalBlock { - } - // Paper end - Fix sticky pistons and BlockPistonRetractEvent - world.setBlock(pos, iblockdata2, 20); -- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); -+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change - world.blockUpdated(pos, iblockdata2.getBlock()); - iblockdata2.updateNeighbourShapes(world, pos, 2); - if (this.isSticky) { -@@ -292,7 +298,14 @@ public class PistonBaseBlock extends DirectionalBlock { - } - } - } else { -- world.removeBlock(pos.relative(enumdirection), false); -+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; fix headless pistons breaking blocks -+ BlockPos headPos = pos.relative(enumdirection); -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston. -+ world.removeBlock(headPos, false); -+ } else { -+ ((ServerLevel) world).getChunkSource().blockChanged(headPos); // ... fix client desync -+ } -+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed - } - - world.playSound((Player) null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F); -diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 1b988b92e80faa1ac224caf9f9e955ac43a4c45a..95d30c2db7e291d65c24feb114b0f3598d280912 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -178,7 +178,7 @@ public abstract class BlockBehaviour implements FeatureElement { - } - - protected void onExplosionHit(BlockState state, ServerLevel world, BlockPos pos, Explosion explosion, BiConsumer stackMerger) { -- if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK) { -+ if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed - Block block = state.getBlock(); - boolean flag = explosion.getIndirectSourceEntity() instanceof Player; - -@@ -257,7 +257,7 @@ public abstract class BlockBehaviour implements FeatureElement { - } - - protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) { -- return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())); -+ return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed - } - - protected boolean canBeReplaced(BlockState state, Fluid fluid) { -@@ -945,6 +945,12 @@ public abstract class BlockBehaviour implements FeatureElement { - return this.legacySolid; - } - -+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed -+ public final boolean isDestroyable() { -+ return getBlock().isDestroyable(); -+ } -+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed -+ - public boolean isValidSpawn(BlockGetter world, BlockPos pos, EntityType type) { - return this.getBlock().properties.isValidSpawn.test(this.asState(), world, pos, type); - } -@@ -1048,7 +1054,7 @@ public abstract class BlockBehaviour implements FeatureElement { - } - - public PushReaction getPistonPushReaction() { -- return this.pushReaction; -+ return !this.isDestroyable() ? PushReaction.BLOCK : this.pushReaction; // Paper - Protect Bedrock and End Portal/Frames from being destroyed - } - - public boolean isSolidRender() { -diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java -index eb409fb5e673d2a343813946cc59cb5da2328eec..83d294f6f48b867d09ea0d339c779011bf4138a5 100644 ---- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java -+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java -@@ -207,6 +207,13 @@ public class PortalForcer { - for (int j = -1; j < 3; ++j) { - for (int k = -1; k < 4; ++k) { - temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal); -+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { -+ if (!this.level.getBlockState(temp).isDestroyable()) { -+ return false; -+ } -+ } -+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed - if (k < 0 && !this.level.getBlockState(temp).isSolid()) { - return false; - } diff --git a/patches/server/0943-Add-config-for-mobs-immune-to-default-effects.patch b/patches/server/0943-Add-config-for-mobs-immune-to-default-effects.patch deleted file mode 100644 index c3b01a16ed..0000000000 --- a/patches/server/0943-Add-config-for-mobs-immune-to-default-effects.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 2 Dec 2020 21:03:02 -0800 -Subject: [PATCH] Add config for mobs immune to default effects - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index e1be143959fbaa1d54af2a1a2c27187d70e6a9e9..244e38db508efa3eebebb6392c4ebb0805367baf 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -602,7 +602,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { - - @Override - public boolean canBeAffected(MobEffectInstance effect) { -- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect); -+ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.wither ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects - } - - private class WitherDoNothingGoal extends Goal { -diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java -index 72e42605c278028480c368762da18f61806d766a..91e521414c3ea5722aac7506b7589fbb399e9636 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Spider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java -@@ -126,7 +126,7 @@ public class Spider extends Monster { - - @Override - public boolean canBeAffected(MobEffectInstance effect) { -- return effect.is(MobEffects.POISON) ? false : super.canBeAffected(effect); -+ return effect.is(MobEffects.POISON) && this.level().paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects - } - - public boolean isClimbing() { -diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -index c295b604f438c62d589ab05ea44c85dbefcb258b..37d3acda84a984bf4f1c44b3d27e2102839d3e8e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -114,6 +114,6 @@ public class WitherSkeleton extends AbstractSkeleton { - - @Override - public boolean canBeAffected(MobEffectInstance effect) { -- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect); -+ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects - } - } diff --git a/patches/server/0943-Deep-clone-nbt-tags-in-PDC.patch b/patches/server/0943-Deep-clone-nbt-tags-in-PDC.patch new file mode 100644 index 0000000000..559c6cddea --- /dev/null +++ b/patches/server/0943-Deep-clone-nbt-tags-in-PDC.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Thu, 26 May 2022 03:30:05 +0300 +Subject: [PATCH] Deep clone nbt tags in PDC + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 3bcc807005a677884255f1ee36cbf1653797ba55..8d13505c36d732f17293c6a6d65cac20919b8b7a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -372,7 +372,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.maxDamage = meta.maxDamage; + this.unhandledTags.copy(meta.unhandledTags.build()); + this.removedTags.addAll(meta.removedTags); +- this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw()); ++ this.persistentDataContainer.putAll(meta.persistentDataContainer.getTagsCloned()); // Paper - deep clone NBT tags + + this.customTag = meta.customTag; + +@@ -1966,7 +1966,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + clone.customTag = this.customTag.copy(); + } + clone.removedTags = Sets.newHashSet(this.removedTags); +- clone.persistentDataContainer = new CraftPersistentDataContainer(this.persistentDataContainer.getRaw(), CraftMetaItem.DATA_TYPE_REGISTRY); ++ clone.persistentDataContainer = new CraftPersistentDataContainer(this.persistentDataContainer.getTagsCloned(), CraftMetaItem.DATA_TYPE_REGISTRY); // Paper - deep clone NBT tags + clone.hideFlag = this.hideFlag; + clone.hideTooltip = this.hideTooltip; + clone.tooltipStyle = this.tooltipStyle; +diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java +index 5a4e7e7150b7c137b077e0b393f17ed35b5aec34..f55fdd57ced259ad5a95878840e98ffaa3db2e05 100644 +--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java ++++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java +@@ -207,4 +207,12 @@ public class CraftPersistentDataContainer implements PersistentDataContainer { + } + } + // Paper end - byte array serialization ++ ++ // Paper start - deep clone tags ++ public Map getTagsCloned() { ++ final Map tags = new HashMap<>(); ++ this.customDataTags.forEach((key, tag) -> tags.put(key, tag.copy())); ++ return tags; ++ } ++ // Paper end - deep clone tags + } diff --git a/patches/server/0944-Deep-clone-nbt-tags-in-PDC.patch b/patches/server/0944-Deep-clone-nbt-tags-in-PDC.patch deleted file mode 100644 index 559c6cddea..0000000000 --- a/patches/server/0944-Deep-clone-nbt-tags-in-PDC.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SoSeDiK -Date: Thu, 26 May 2022 03:30:05 +0300 -Subject: [PATCH] Deep clone nbt tags in PDC - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 3bcc807005a677884255f1ee36cbf1653797ba55..8d13505c36d732f17293c6a6d65cac20919b8b7a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -372,7 +372,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.maxDamage = meta.maxDamage; - this.unhandledTags.copy(meta.unhandledTags.build()); - this.removedTags.addAll(meta.removedTags); -- this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw()); -+ this.persistentDataContainer.putAll(meta.persistentDataContainer.getTagsCloned()); // Paper - deep clone NBT tags - - this.customTag = meta.customTag; - -@@ -1966,7 +1966,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - clone.customTag = this.customTag.copy(); - } - clone.removedTags = Sets.newHashSet(this.removedTags); -- clone.persistentDataContainer = new CraftPersistentDataContainer(this.persistentDataContainer.getRaw(), CraftMetaItem.DATA_TYPE_REGISTRY); -+ clone.persistentDataContainer = new CraftPersistentDataContainer(this.persistentDataContainer.getTagsCloned(), CraftMetaItem.DATA_TYPE_REGISTRY); // Paper - deep clone NBT tags - clone.hideFlag = this.hideFlag; - clone.hideTooltip = this.hideTooltip; - clone.tooltipStyle = this.tooltipStyle; -diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -index 5a4e7e7150b7c137b077e0b393f17ed35b5aec34..f55fdd57ced259ad5a95878840e98ffaa3db2e05 100644 ---- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java -@@ -207,4 +207,12 @@ public class CraftPersistentDataContainer implements PersistentDataContainer { - } - } - // Paper end - byte array serialization -+ -+ // Paper start - deep clone tags -+ public Map getTagsCloned() { -+ final Map tags = new HashMap<>(); -+ this.customDataTags.forEach((key, tag) -> tags.put(key, tag.copy())); -+ return tags; -+ } -+ // Paper end - deep clone tags - } diff --git a/patches/server/0944-Support-old-UUID-format-for-NBT.patch b/patches/server/0944-Support-old-UUID-format-for-NBT.patch new file mode 100644 index 0000000000..68ff8a5255 --- /dev/null +++ b/patches/server/0944-Support-old-UUID-format-for-NBT.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 29 Jun 2020 03:26:17 -0400 +Subject: [PATCH] Support old UUID format for NBT + +We have stored UUID in plenty of places that did not get DFU'd + +So just look for old format and load it if it exists. + +diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java +index e88161e662d5605b50aead673c9b3794874e5f7f..d7bb00a946346dff0b0269cbd65276e146a63fb0 100644 +--- a/src/main/java/net/minecraft/nbt/CompoundTag.java ++++ b/src/main/java/net/minecraft/nbt/CompoundTag.java +@@ -232,6 +232,12 @@ public class CompoundTag implements Tag { + } + + public void putUUID(String key, UUID value) { ++ // Paper start - Support old UUID format ++ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { ++ this.tags.remove(key + "Most"); ++ this.tags.remove(key + "Least"); ++ } ++ // Paper end - Support old UUID format + this.tags.put(key, NbtUtils.createUUID(value)); + } + +@@ -240,10 +246,20 @@ public class CompoundTag implements Tag { + * You must use {@link #hasUUID(String)} before or else it will throw an NPE. + */ + public UUID getUUID(String key) { ++ // Paper start - Support old UUID format ++ if (!contains(key, 11) && this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { ++ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least")); ++ } ++ // Paper end - Support old UUID format + return NbtUtils.loadUUID(this.get(key)); + } + + public boolean hasUUID(String key) { ++ // Paper start - Support old UUID format ++ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { ++ return true; ++ } ++ // Paper end - Support old UUID format + Tag tag = this.get(key); + return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4; + } +diff --git a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java +index 78863e72239a0f3535bc85758479da84d58c11c1..38bbe39a5cd96710b208d70ed78619057bb6e6fa 100644 +--- a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java ++++ b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java +@@ -20,9 +20,10 @@ public record ResolvableProfile(Optional name, Optional id, Proper + instance -> instance.group( + ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile::name), + UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile::id), ++ UUIDUtil.STRING_CODEC.lenientOptionalFieldOf("Id").forGetter($ -> Optional.empty()), // Paper + ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", new PropertyMap()).forGetter(ResolvableProfile::properties) + ) +- .apply(instance, ResolvableProfile::new) ++ .apply(instance, (s, uuid, uuid2, propertyMap) -> new ResolvableProfile(s, uuid2.or(() -> uuid), propertyMap)) // Paper + ); + public static final Codec CODEC = Codec.withAlternative( + FULL_CODEC, ExtraCodecs.PLAYER_NAME, name -> new ResolvableProfile(Optional.of(name), Optional.empty(), new PropertyMap()) diff --git a/patches/server/0945-Fix-shield-disable-inconsistency.patch b/patches/server/0945-Fix-shield-disable-inconsistency.patch new file mode 100644 index 0000000000..0f02785268 --- /dev/null +++ b/patches/server/0945-Fix-shield-disable-inconsistency.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 26 Apr 2024 19:08:37 -0700 +Subject: [PATCH] Fix shield disable inconsistency + +In vanilla, if the damage source is tagged as a projectile, +it will not disable the shield if the attacker is holding +an axe item. + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 49b3d8d2bc34c0785f143bbc8976308f5bf8c9de..f6d55ff3027bb7f0dcef186c52d48d9c5358ffd0 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2424,7 +2424,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING)); + Entity entity = damagesource.getDirectEntity(); + +- if (entity instanceof LivingEntity) { ++ if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency + this.blockUsingShield((LivingEntity) entity); + } + } diff --git a/patches/server/0945-Support-old-UUID-format-for-NBT.patch b/patches/server/0945-Support-old-UUID-format-for-NBT.patch deleted file mode 100644 index 68ff8a5255..0000000000 --- a/patches/server/0945-Support-old-UUID-format-for-NBT.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 29 Jun 2020 03:26:17 -0400 -Subject: [PATCH] Support old UUID format for NBT - -We have stored UUID in plenty of places that did not get DFU'd - -So just look for old format and load it if it exists. - -diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java -index e88161e662d5605b50aead673c9b3794874e5f7f..d7bb00a946346dff0b0269cbd65276e146a63fb0 100644 ---- a/src/main/java/net/minecraft/nbt/CompoundTag.java -+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java -@@ -232,6 +232,12 @@ public class CompoundTag implements Tag { - } - - public void putUUID(String key, UUID value) { -+ // Paper start - Support old UUID format -+ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -+ this.tags.remove(key + "Most"); -+ this.tags.remove(key + "Least"); -+ } -+ // Paper end - Support old UUID format - this.tags.put(key, NbtUtils.createUUID(value)); - } - -@@ -240,10 +246,20 @@ public class CompoundTag implements Tag { - * You must use {@link #hasUUID(String)} before or else it will throw an NPE. - */ - public UUID getUUID(String key) { -+ // Paper start - Support old UUID format -+ if (!contains(key, 11) && this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -+ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least")); -+ } -+ // Paper end - Support old UUID format - return NbtUtils.loadUUID(this.get(key)); - } - - public boolean hasUUID(String key) { -+ // Paper start - Support old UUID format -+ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -+ return true; -+ } -+ // Paper end - Support old UUID format - Tag tag = this.get(key); - return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4; - } -diff --git a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java -index 78863e72239a0f3535bc85758479da84d58c11c1..38bbe39a5cd96710b208d70ed78619057bb6e6fa 100644 ---- a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java -+++ b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java -@@ -20,9 +20,10 @@ public record ResolvableProfile(Optional name, Optional id, Proper - instance -> instance.group( - ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile::name), - UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile::id), -+ UUIDUtil.STRING_CODEC.lenientOptionalFieldOf("Id").forGetter($ -> Optional.empty()), // Paper - ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", new PropertyMap()).forGetter(ResolvableProfile::properties) - ) -- .apply(instance, ResolvableProfile::new) -+ .apply(instance, (s, uuid, uuid2, propertyMap) -> new ResolvableProfile(s, uuid2.or(() -> uuid), propertyMap)) // Paper - ); - public static final Codec CODEC = Codec.withAlternative( - FULL_CODEC, ExtraCodecs.PLAYER_NAME, name -> new ResolvableProfile(Optional.of(name), Optional.empty(), new PropertyMap()) diff --git a/patches/server/0946-Fix-shield-disable-inconsistency.patch b/patches/server/0946-Fix-shield-disable-inconsistency.patch deleted file mode 100644 index 8d372bca9d..0000000000 --- a/patches/server/0946-Fix-shield-disable-inconsistency.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 26 Apr 2024 19:08:37 -0700 -Subject: [PATCH] Fix shield disable inconsistency - -In vanilla, if the damage source is tagged as a projectile, -it will not disable the shield if the attacker is holding -an axe item. - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 7196340fefd95845f290329faef489f2b2626ecb..b33dd288065b665e6feb642d090de1fd6e725448 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2426,7 +2426,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING)); - Entity entity = damagesource.getDirectEntity(); - -- if (entity instanceof LivingEntity) { -+ if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency - this.blockUsingShield((LivingEntity) entity); - } - } diff --git a/patches/server/0946-Handle-Large-Packets-disconnecting-client.patch b/patches/server/0946-Handle-Large-Packets-disconnecting-client.patch new file mode 100644 index 0000000000..32e463a242 --- /dev/null +++ b/patches/server/0946-Handle-Large-Packets-disconnecting-client.patch @@ -0,0 +1,135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 27 Nov 2018 21:18:06 -0500 +Subject: [PATCH] Handle Large Packets disconnecting client + +If a players inventory is too big to send in a single packet, +split the inventory set into multiple packets instead. + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index a8dfe7a4b3d01bf75587be078f471d1ef1d7a667..ea16dfa718b526d6520d7fcfc21d28f972f1f2bf 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -176,6 +176,21 @@ public class Connection extends SimpleChannelInboundHandler> { + } + + public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) { ++ // Paper start - Handle large packets disconnecting client ++ if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) { ++ final Packet packet = packetTooLargeException.getPacket(); ++ if (packet.packetTooLarge(this)) { ++ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); ++ return; ++ } else if (packet.isSkippable()) { ++ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); ++ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); ++ return; ++ } else { ++ throwable = throwable.getCause(); ++ } ++ } ++ // Paper end - Handle large packets disconnecting client + if (throwable instanceof SkipPacketException) { + Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); + } else { +diff --git a/src/main/java/net/minecraft/network/PacketEncoder.java b/src/main/java/net/minecraft/network/PacketEncoder.java +index 046bfc212b640de174b300e7a05cc30bb3cac93e..af3ec112e142a2c91c46882dad6180b18f39eec2 100644 +--- a/src/main/java/net/minecraft/network/PacketEncoder.java ++++ b/src/main/java/net/minecraft/network/PacketEncoder.java +@@ -40,7 +40,33 @@ public class PacketEncoder extends MessageToByteEncode + + throw var9; + } finally { ++ // Paper start - Handle large packets disconnecting client ++ int packetLength = byteBuf.readableBytes(); ++ if (packetLength > MAX_PACKET_SIZE || (packetLength > MAX_FINAL_PACKET_SIZE && packet.hasLargePacketFallback())) { ++ throw new PacketTooLargeException(packet, packetLength); ++ } ++ // Paper end - Handle large packets disconnecting client + ProtocolSwapHandler.handleOutboundTerminalPacket(channelHandlerContext, packet); + } + } ++ ++ // Paper start ++ // packet size is encoded into 3-byte varint ++ private static final int MAX_FINAL_PACKET_SIZE = (1 << 21) - 1; ++ // Vanilla Max size for the encoder (before compression) ++ private static final int MAX_PACKET_SIZE = 8388608; ++ ++ public static class PacketTooLargeException extends RuntimeException { ++ private final Packet packet; ++ ++ PacketTooLargeException(Packet packet, int packetLength) { ++ super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE); ++ this.packet = packet; ++ } ++ ++ public Packet getPacket() { ++ return this.packet; ++ } ++ } ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main/java/net/minecraft/network/protocol/Packet.java +index 4c776c591dd0a7b36945a6487fdfe86d1187b4af..82fc12ffbd1585b4a8d09a025914830af77b0f8d 100644 +--- a/src/main/java/net/minecraft/network/protocol/Packet.java ++++ b/src/main/java/net/minecraft/network/protocol/Packet.java +@@ -11,6 +11,19 @@ public interface Packet { + + void handle(T listener); + ++ // Paper start ++ default boolean hasLargePacketFallback() { ++ return false; ++ } ++ ++ /** ++ * override {@link #hasLargePacketFallback()} to return true when overriding in subclasses ++ */ ++ default boolean packetTooLarge(net.minecraft.network.Connection manager) { ++ return false; ++ } ++ // Paper end ++ + default boolean isSkippable() { + return false; + } +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java +index f53c74fb1863a2d1268a4ddf8cf69d1fda32d73f..8d5939e03a065197af125d95a10134abbccd07ec 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java +@@ -36,6 +36,21 @@ public class ClientboundContainerSetContentPacket implements Packet 2097152) { ++ if (i > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder + throw new RuntimeException("Chunk Packet trying to allocate too much memory on read."); + } else { + this.buffer = new byte[i]; diff --git a/patches/server/0947-Fix-ItemFlags.patch b/patches/server/0947-Fix-ItemFlags.patch new file mode 100644 index 0000000000..e045394f3c --- /dev/null +++ b/patches/server/0947-Fix-ItemFlags.patch @@ -0,0 +1,199 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 27 Apr 2024 12:16:38 -0700 +Subject: [PATCH] Fix ItemFlags + +Re-adds missing functionality for HIDE_DESTROYS and +HIDE_PLACED_ON. Also adds new flag in HIDE_STORED_ENCHANTS +which was split from HIDE_ADDITIONAL_TOOLTIP. + +== AT == +public net.minecraft.world.item.AdventureModePredicate predicates + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +index 73fe41322e0349ad1d46a760f621b6c91112e90e..19af55ec2bf62b70bd3be44f499b32f5efe71ab1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +@@ -38,7 +38,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage + getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { + this.enchantments = buildEnchantments(itemEnchantments); + if (!itemEnchantments.showInTooltip) { +- this.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); ++ this.addItemFlags(ItemFlag.HIDE_STORED_ENCHANTS); // Paper - new ItemFlag + } + }); + } +@@ -53,7 +53,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage + void applyToItem(CraftMetaItem.Applicator itemTag) { + super.applyToItem(itemTag); + +- this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_ADDITIONAL_TOOLTIP); ++ this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_STORED_ENCHANTS); + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 8d13505c36d732f17293c6a6d65cac20919b8b7a..6b3eed94c26bc16177f9b9fadd140f9a89163af2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -275,6 +275,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + static final ItemMetaKeyType HIDE_ADDITIONAL_TOOLTIP = new ItemMetaKeyType(DataComponents.HIDE_ADDITIONAL_TOOLTIP); + @Specific(Specific.To.NBT) + static final ItemMetaKeyType CUSTOM_DATA = new ItemMetaKeyType<>(DataComponents.CUSTOM_DATA); ++ // Paper start - fix ItemFlags ++ static final ItemMetaKeyType CAN_PLACE_ON = new ItemMetaKeyType<>(DataComponents.CAN_PLACE_ON); ++ static final ItemMetaKeyType CAN_BREAK = new ItemMetaKeyType<>(DataComponents.CAN_BREAK); ++ private List canPlaceOnPredicates; ++ private List canBreakPredicates; ++ // Paper end - fix ItemFlags + + // We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304 + private Component displayName; +@@ -377,6 +383,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.customTag = meta.customTag; + + this.version = meta.version; ++ // Paper start ++ this.canPlaceOnPredicates = meta.canPlaceOnPredicates; ++ this.canBreakPredicates = meta.canBreakPredicates; ++ // Paper end + } + + CraftMetaItem(DataComponentPatch tag) { +@@ -496,6 +506,20 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.customTag = null; + } + }); ++ // Paper start - fix ItemFlags ++ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { ++ this.canPlaceOnPredicates = List.copyOf(data.predicates); ++ if (!data.showInTooltip()) { ++ this.addItemFlags(ItemFlag.HIDE_PLACED_ON); ++ } ++ }); ++ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_BREAK).ifPresent(data -> { ++ this.canBreakPredicates = List.copyOf(data.predicates); ++ if (!data.showInTooltip()) { ++ this.addItemFlags(ItemFlag.HIDE_DESTROYS); ++ } ++ }); ++ // Paper end - fix ItemFlags + + Set, Optional>> keys = tag.entrySet(); + for (Map.Entry, Optional> key : keys) { +@@ -735,7 +759,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + try { + CompoundTag unhandledTag = NbtIo.readCompressed(buf, NbtAccounter.unlimitedHeap()); + DataComponentPatch unhandledPatch = DataComponentPatch.CODEC.parse(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), unhandledTag).result().get(); +- this.unhandledTags.copy(unhandledPatch); ++ // Paper start ++ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { ++ this.canPlaceOnPredicates = List.copyOf(data.predicates); ++ }); ++ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_BREAK).ifPresent(data -> { ++ this.canBreakPredicates = List.copyOf(data.predicates); ++ }); ++ this.unhandledTags.copy(unhandledPatch.forget(type -> type == CraftMetaItem.CAN_PLACE_ON.TYPE || type == CraftMetaItem.CAN_BREAK.TYPE)); ++ // Paper end + + for (Entry, Optional> entry : unhandledPatch.entrySet()) { + // Move removed unhandled tags to dedicated removedTags +@@ -1006,6 +1038,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + itemTag.put(CraftMetaItem.MAX_DAMAGE, this.maxDamage); + } + ++ // Paper start ++ if (this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty()) { ++ itemTag.put(CraftMetaItem.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); ++ } ++ if (this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty()) { ++ itemTag.put(CraftMetaItem.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); ++ } ++ // Paper end ++ + for (Map.Entry, Optional> e : this.unhandledTags.build().entrySet()) { + e.getValue().ifPresent((value) -> { + itemTag.builder.set((DataComponentType) e.getKey(), value); +@@ -1096,7 +1137,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Overridden + boolean isEmpty() { +- return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null); ++ return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper + } + + // Paper start +@@ -1889,6 +1930,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + && (this.hasJukeboxPlayable() ? that.hasJukeboxPlayable() && this.jukebox.equals(that.jukebox) : !that.hasJukeboxPlayable()) + && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) + && (this.hasMaxDamage() ? that.hasMaxDamage() && this.maxDamage.equals(that.maxDamage) : !that.hasMaxDamage()) ++ && (this.canPlaceOnPredicates != null ? that.canPlaceOnPredicates != null && this.canPlaceOnPredicates.equals(that.canPlaceOnPredicates) : that.canPlaceOnPredicates == null) // Paper ++ && (this.canBreakPredicates != null ? that.canBreakPredicates != null && this.canBreakPredicates.equals(that.canBreakPredicates) : that.canBreakPredicates == null) // Paper + && (this.version == that.version); + } + +@@ -1941,6 +1984,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + hash = 61 * hash + (this.hasDamage() ? this.damage : 0); + hash = 61 * hash + (this.hasMaxDamage() ? 1231 : 1237); + hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); ++ hash = 61 * hash + (this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates.hashCode() : 0); // Paper ++ hash = 61 * hash + (this.canBreakPredicates != null ? this.canBreakPredicates.hashCode() : 0); // Paper + hash = 61 * hash + this.version; + return hash; + } +@@ -1998,6 +2043,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + clone.damage = this.damage; + clone.maxDamage = this.maxDamage; + clone.version = this.version; ++ // Paper start ++ if (this.canPlaceOnPredicates != null) { ++ clone.canPlaceOnPredicates = List.copyOf(this.canPlaceOnPredicates); ++ } ++ if (this.canBreakPredicates != null) { ++ clone.canBreakPredicates = List.copyOf(this.canBreakPredicates); ++ } ++ // Paper end + return clone; + } catch (CloneNotSupportedException e) { + throw new Error(e); +@@ -2142,6 +2195,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + } + ++ // Paper start ++ final boolean canBreakAddToUnhandled = this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty(); ++ if (canBreakAddToUnhandled) { ++ this.unhandledTags.set(DataComponents.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); ++ } ++ final boolean canPlaceOnAddToUnhandled = this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty(); ++ if (canPlaceOnAddToUnhandled) { ++ this.unhandledTags.set(DataComponents.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); ++ } ++ // Paper end + if (!this.unhandledTags.isEmpty()) { + net.minecraft.nbt.Tag unhandled = DataComponentPatch.CODEC.encodeStart(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), this.unhandledTags.build()).getOrThrow(IllegalStateException::new); + try { +@@ -2152,6 +2215,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex); + } + } ++ // Paper start ++ if (canBreakAddToUnhandled) { ++ this.unhandledTags.clear(DataComponents.CAN_BREAK); ++ } ++ if (canPlaceOnAddToUnhandled) { ++ this.unhandledTags.clear(DataComponents.CAN_PLACE_ON); ++ } ++ // Paper end + + if (!this.removedTags.isEmpty()) { + RegistryAccess registryAccess = CraftRegistry.getMinecraftRegistry(); +@@ -2312,6 +2383,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + CraftMetaItem.MAX_DAMAGE.TYPE, + CraftMetaItem.CUSTOM_DATA.TYPE, + CraftMetaItem.ATTRIBUTES.TYPE, ++ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper ++ CraftMetaItem.CAN_BREAK.TYPE, // Paper + CraftMetaArmor.TRIM.TYPE, + CraftMetaArmorStand.ENTITY_TAG.TYPE, + CraftMetaBanner.PATTERNS.TYPE, diff --git a/patches/server/0947-Handle-Large-Packets-disconnecting-client.patch b/patches/server/0947-Handle-Large-Packets-disconnecting-client.patch deleted file mode 100644 index 32e463a242..0000000000 --- a/patches/server/0947-Handle-Large-Packets-disconnecting-client.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 27 Nov 2018 21:18:06 -0500 -Subject: [PATCH] Handle Large Packets disconnecting client - -If a players inventory is too big to send in a single packet, -split the inventory set into multiple packets instead. - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index a8dfe7a4b3d01bf75587be078f471d1ef1d7a667..ea16dfa718b526d6520d7fcfc21d28f972f1f2bf 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -176,6 +176,21 @@ public class Connection extends SimpleChannelInboundHandler> { - } - - public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) { -+ // Paper start - Handle large packets disconnecting client -+ if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) { -+ final Packet packet = packetTooLargeException.getPacket(); -+ if (packet.packetTooLarge(this)) { -+ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); -+ return; -+ } else if (packet.isSkippable()) { -+ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); -+ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); -+ return; -+ } else { -+ throwable = throwable.getCause(); -+ } -+ } -+ // Paper end - Handle large packets disconnecting client - if (throwable instanceof SkipPacketException) { - Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); - } else { -diff --git a/src/main/java/net/minecraft/network/PacketEncoder.java b/src/main/java/net/minecraft/network/PacketEncoder.java -index 046bfc212b640de174b300e7a05cc30bb3cac93e..af3ec112e142a2c91c46882dad6180b18f39eec2 100644 ---- a/src/main/java/net/minecraft/network/PacketEncoder.java -+++ b/src/main/java/net/minecraft/network/PacketEncoder.java -@@ -40,7 +40,33 @@ public class PacketEncoder extends MessageToByteEncode - - throw var9; - } finally { -+ // Paper start - Handle large packets disconnecting client -+ int packetLength = byteBuf.readableBytes(); -+ if (packetLength > MAX_PACKET_SIZE || (packetLength > MAX_FINAL_PACKET_SIZE && packet.hasLargePacketFallback())) { -+ throw new PacketTooLargeException(packet, packetLength); -+ } -+ // Paper end - Handle large packets disconnecting client - ProtocolSwapHandler.handleOutboundTerminalPacket(channelHandlerContext, packet); - } - } -+ -+ // Paper start -+ // packet size is encoded into 3-byte varint -+ private static final int MAX_FINAL_PACKET_SIZE = (1 << 21) - 1; -+ // Vanilla Max size for the encoder (before compression) -+ private static final int MAX_PACKET_SIZE = 8388608; -+ -+ public static class PacketTooLargeException extends RuntimeException { -+ private final Packet packet; -+ -+ PacketTooLargeException(Packet packet, int packetLength) { -+ super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE); -+ this.packet = packet; -+ } -+ -+ public Packet getPacket() { -+ return this.packet; -+ } -+ } -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main/java/net/minecraft/network/protocol/Packet.java -index 4c776c591dd0a7b36945a6487fdfe86d1187b4af..82fc12ffbd1585b4a8d09a025914830af77b0f8d 100644 ---- a/src/main/java/net/minecraft/network/protocol/Packet.java -+++ b/src/main/java/net/minecraft/network/protocol/Packet.java -@@ -11,6 +11,19 @@ public interface Packet { - - void handle(T listener); - -+ // Paper start -+ default boolean hasLargePacketFallback() { -+ return false; -+ } -+ -+ /** -+ * override {@link #hasLargePacketFallback()} to return true when overriding in subclasses -+ */ -+ default boolean packetTooLarge(net.minecraft.network.Connection manager) { -+ return false; -+ } -+ // Paper end -+ - default boolean isSkippable() { - return false; - } -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java -index f53c74fb1863a2d1268a4ddf8cf69d1fda32d73f..8d5939e03a065197af125d95a10134abbccd07ec 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java -@@ -36,6 +36,21 @@ public class ClientboundContainerSetContentPacket implements Packet 2097152) { -+ if (i > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder - throw new RuntimeException("Chunk Packet trying to allocate too much memory on read."); - } else { - this.buffer = new byte[i]; diff --git a/patches/server/0948-Fix-ItemFlags.patch b/patches/server/0948-Fix-ItemFlags.patch deleted file mode 100644 index e045394f3c..0000000000 --- a/patches/server/0948-Fix-ItemFlags.patch +++ /dev/null @@ -1,199 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 27 Apr 2024 12:16:38 -0700 -Subject: [PATCH] Fix ItemFlags - -Re-adds missing functionality for HIDE_DESTROYS and -HIDE_PLACED_ON. Also adds new flag in HIDE_STORED_ENCHANTS -which was split from HIDE_ADDITIONAL_TOOLTIP. - -== AT == -public net.minecraft.world.item.AdventureModePredicate predicates - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -index 73fe41322e0349ad1d46a760f621b6c91112e90e..19af55ec2bf62b70bd3be44f499b32f5efe71ab1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -@@ -38,7 +38,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage - getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { - this.enchantments = buildEnchantments(itemEnchantments); - if (!itemEnchantments.showInTooltip) { -- this.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); -+ this.addItemFlags(ItemFlag.HIDE_STORED_ENCHANTS); // Paper - new ItemFlag - } - }); - } -@@ -53,7 +53,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage - void applyToItem(CraftMetaItem.Applicator itemTag) { - super.applyToItem(itemTag); - -- this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_ADDITIONAL_TOOLTIP); -+ this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_STORED_ENCHANTS); - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 8d13505c36d732f17293c6a6d65cac20919b8b7a..6b3eed94c26bc16177f9b9fadd140f9a89163af2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -275,6 +275,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - static final ItemMetaKeyType HIDE_ADDITIONAL_TOOLTIP = new ItemMetaKeyType(DataComponents.HIDE_ADDITIONAL_TOOLTIP); - @Specific(Specific.To.NBT) - static final ItemMetaKeyType CUSTOM_DATA = new ItemMetaKeyType<>(DataComponents.CUSTOM_DATA); -+ // Paper start - fix ItemFlags -+ static final ItemMetaKeyType CAN_PLACE_ON = new ItemMetaKeyType<>(DataComponents.CAN_PLACE_ON); -+ static final ItemMetaKeyType CAN_BREAK = new ItemMetaKeyType<>(DataComponents.CAN_BREAK); -+ private List canPlaceOnPredicates; -+ private List canBreakPredicates; -+ // Paper end - fix ItemFlags - - // We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304 - private Component displayName; -@@ -377,6 +383,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.customTag = meta.customTag; - - this.version = meta.version; -+ // Paper start -+ this.canPlaceOnPredicates = meta.canPlaceOnPredicates; -+ this.canBreakPredicates = meta.canBreakPredicates; -+ // Paper end - } - - CraftMetaItem(DataComponentPatch tag) { -@@ -496,6 +506,20 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.customTag = null; - } - }); -+ // Paper start - fix ItemFlags -+ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { -+ this.canPlaceOnPredicates = List.copyOf(data.predicates); -+ if (!data.showInTooltip()) { -+ this.addItemFlags(ItemFlag.HIDE_PLACED_ON); -+ } -+ }); -+ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_BREAK).ifPresent(data -> { -+ this.canBreakPredicates = List.copyOf(data.predicates); -+ if (!data.showInTooltip()) { -+ this.addItemFlags(ItemFlag.HIDE_DESTROYS); -+ } -+ }); -+ // Paper end - fix ItemFlags - - Set, Optional>> keys = tag.entrySet(); - for (Map.Entry, Optional> key : keys) { -@@ -735,7 +759,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - try { - CompoundTag unhandledTag = NbtIo.readCompressed(buf, NbtAccounter.unlimitedHeap()); - DataComponentPatch unhandledPatch = DataComponentPatch.CODEC.parse(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), unhandledTag).result().get(); -- this.unhandledTags.copy(unhandledPatch); -+ // Paper start -+ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { -+ this.canPlaceOnPredicates = List.copyOf(data.predicates); -+ }); -+ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_BREAK).ifPresent(data -> { -+ this.canBreakPredicates = List.copyOf(data.predicates); -+ }); -+ this.unhandledTags.copy(unhandledPatch.forget(type -> type == CraftMetaItem.CAN_PLACE_ON.TYPE || type == CraftMetaItem.CAN_BREAK.TYPE)); -+ // Paper end - - for (Entry, Optional> entry : unhandledPatch.entrySet()) { - // Move removed unhandled tags to dedicated removedTags -@@ -1006,6 +1038,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - itemTag.put(CraftMetaItem.MAX_DAMAGE, this.maxDamage); - } - -+ // Paper start -+ if (this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty()) { -+ itemTag.put(CraftMetaItem.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); -+ } -+ if (this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty()) { -+ itemTag.put(CraftMetaItem.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); -+ } -+ // Paper end -+ - for (Map.Entry, Optional> e : this.unhandledTags.build().entrySet()) { - e.getValue().ifPresent((value) -> { - itemTag.builder.set((DataComponentType) e.getKey(), value); -@@ -1096,7 +1137,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Overridden - boolean isEmpty() { -- return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null); -+ return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper - } - - // Paper start -@@ -1889,6 +1930,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - && (this.hasJukeboxPlayable() ? that.hasJukeboxPlayable() && this.jukebox.equals(that.jukebox) : !that.hasJukeboxPlayable()) - && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) - && (this.hasMaxDamage() ? that.hasMaxDamage() && this.maxDamage.equals(that.maxDamage) : !that.hasMaxDamage()) -+ && (this.canPlaceOnPredicates != null ? that.canPlaceOnPredicates != null && this.canPlaceOnPredicates.equals(that.canPlaceOnPredicates) : that.canPlaceOnPredicates == null) // Paper -+ && (this.canBreakPredicates != null ? that.canBreakPredicates != null && this.canBreakPredicates.equals(that.canBreakPredicates) : that.canBreakPredicates == null) // Paper - && (this.version == that.version); - } - -@@ -1941,6 +1984,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - hash = 61 * hash + (this.hasDamage() ? this.damage : 0); - hash = 61 * hash + (this.hasMaxDamage() ? 1231 : 1237); - hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); -+ hash = 61 * hash + (this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates.hashCode() : 0); // Paper -+ hash = 61 * hash + (this.canBreakPredicates != null ? this.canBreakPredicates.hashCode() : 0); // Paper - hash = 61 * hash + this.version; - return hash; - } -@@ -1998,6 +2043,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - clone.damage = this.damage; - clone.maxDamage = this.maxDamage; - clone.version = this.version; -+ // Paper start -+ if (this.canPlaceOnPredicates != null) { -+ clone.canPlaceOnPredicates = List.copyOf(this.canPlaceOnPredicates); -+ } -+ if (this.canBreakPredicates != null) { -+ clone.canBreakPredicates = List.copyOf(this.canBreakPredicates); -+ } -+ // Paper end - return clone; - } catch (CloneNotSupportedException e) { - throw new Error(e); -@@ -2142,6 +2195,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - } - -+ // Paper start -+ final boolean canBreakAddToUnhandled = this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty(); -+ if (canBreakAddToUnhandled) { -+ this.unhandledTags.set(DataComponents.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); -+ } -+ final boolean canPlaceOnAddToUnhandled = this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty(); -+ if (canPlaceOnAddToUnhandled) { -+ this.unhandledTags.set(DataComponents.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); -+ } -+ // Paper end - if (!this.unhandledTags.isEmpty()) { - net.minecraft.nbt.Tag unhandled = DataComponentPatch.CODEC.encodeStart(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), this.unhandledTags.build()).getOrThrow(IllegalStateException::new); - try { -@@ -2152,6 +2215,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex); - } - } -+ // Paper start -+ if (canBreakAddToUnhandled) { -+ this.unhandledTags.clear(DataComponents.CAN_BREAK); -+ } -+ if (canPlaceOnAddToUnhandled) { -+ this.unhandledTags.clear(DataComponents.CAN_PLACE_ON); -+ } -+ // Paper end - - if (!this.removedTags.isEmpty()) { - RegistryAccess registryAccess = CraftRegistry.getMinecraftRegistry(); -@@ -2312,6 +2383,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - CraftMetaItem.MAX_DAMAGE.TYPE, - CraftMetaItem.CUSTOM_DATA.TYPE, - CraftMetaItem.ATTRIBUTES.TYPE, -+ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper -+ CraftMetaItem.CAN_BREAK.TYPE, // Paper - CraftMetaArmor.TRIM.TYPE, - CraftMetaArmorStand.ENTITY_TAG.TYPE, - CraftMetaBanner.PATTERNS.TYPE, diff --git a/patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch b/patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch new file mode 100644 index 0000000000..ef4efc0ef7 --- /dev/null +++ b/patches/server/0948-Fix-helmet-damage-reduction-inconsistencies.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sat, 27 Apr 2024 21:51:58 +0200 +Subject: [PATCH] Fix helmet damage reduction inconsistencies + +Affect the falling stalactite damage type where the +reduction is not applied like in Vanilla + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 96b901d07718d8926a2175925e867b4417c3947c..6c60bb4f4d1133844a4232df518c062216847fdc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1226,7 +1226,7 @@ public class CraftEventFactory { + modifiers.put(DamageModifier.FREEZING, freezingModifier); + modifierFunctions.put(DamageModifier.FREEZING, freezing); + } +- if (source.is(DamageTypes.FALLING_BLOCK) || source.is(DamageTypes.FALLING_ANVIL)) { ++ if (source.is(DamageTypeTags.DAMAGES_HELMET)) { // Paper + modifiers.put(DamageModifier.HARD_HAT, hardHatModifier); + modifierFunctions.put(DamageModifier.HARD_HAT, hardHat); + } diff --git a/patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch b/patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch deleted file mode 100644 index ef4efc0ef7..0000000000 --- a/patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Sat, 27 Apr 2024 21:51:58 +0200 -Subject: [PATCH] Fix helmet damage reduction inconsistencies - -Affect the falling stalactite damage type where the -reduction is not applied like in Vanilla - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 96b901d07718d8926a2175925e867b4417c3947c..6c60bb4f4d1133844a4232df518c062216847fdc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1226,7 +1226,7 @@ public class CraftEventFactory { - modifiers.put(DamageModifier.FREEZING, freezingModifier); - modifierFunctions.put(DamageModifier.FREEZING, freezing); - } -- if (source.is(DamageTypes.FALLING_BLOCK) || source.is(DamageTypes.FALLING_ANVIL)) { -+ if (source.is(DamageTypeTags.DAMAGES_HELMET)) { // Paper - modifiers.put(DamageModifier.HARD_HAT, hardHatModifier); - modifierFunctions.put(DamageModifier.HARD_HAT, hardHat); - } diff --git a/patches/server/0949-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch b/patches/server/0949-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch new file mode 100644 index 0000000000..035254da67 --- /dev/null +++ b/patches/server/0949-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 27 Apr 2024 09:44:53 -0700 +Subject: [PATCH] Revert to vanilla handling of LivingEntity#actuallyHurt + + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index f6d55ff3027bb7f0dcef186c52d48d9c5358ffd0..563e008740bf2017a1767470a2e34629dfa5cfa1 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1455,7 +1455,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + amount = 0.0F; + } + +- float f1 = amount; ++ float f1 = amount; final float originalAmount = f1; // Paper - revert to vanilla #hurt - OBFHELPER + boolean flag = amount > 0.0F && this.isDamageSourceBlocked(source); // Copied from below + float f2 = 0.0F; + +@@ -1513,6 +1513,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (!this.actuallyHurt(world, source, (float) event.getFinalDamage() - this.lastHurt, event)) { + return false; + } ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. + // CraftBukkit end + this.lastHurt = amount; + flag1 = false; +@@ -1521,6 +1522,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (!this.actuallyHurt(world, source, (float) event.getFinalDamage(), event)) { + return false; + } ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. + this.lastHurt = amount; + this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks + // this.actuallyHurt(worldserver, damagesource, f); +@@ -2486,12 +2488,12 @@ public abstract class LivingEntity extends Entity implements Attackable { + + return true; + } else { +- return originalDamage > 0; ++ return true; // Paper - return false ONLY if event was cancelled + } + // CraftBukkit end + } + } +- return false; // CraftBukkit ++ return true; // CraftBukkit // Paper - return false ONLY if event was cancelled + } + + public CombatTracker getCombatTracker() { diff --git a/patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch b/patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch deleted file mode 100644 index e31dca1bf5..0000000000 --- a/patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 27 Apr 2024 09:44:53 -0700 -Subject: [PATCH] Revert to vanilla handling of LivingEntity#actuallyHurt - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index b33dd288065b665e6feb642d090de1fd6e725448..0cb9de4ff9ba0611a3bfc444088accb07ee19252 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1457,7 +1457,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - amount = 0.0F; - } - -- float f1 = amount; -+ float f1 = amount; final float originalAmount = f1; // Paper - revert to vanilla #hurt - OBFHELPER - boolean flag = amount > 0.0F && this.isDamageSourceBlocked(source); // Copied from below - float f2 = 0.0F; - -@@ -1515,6 +1515,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (!this.actuallyHurt(world, source, (float) event.getFinalDamage() - this.lastHurt, event)) { - return false; - } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. - // CraftBukkit end - this.lastHurt = amount; - flag1 = false; -@@ -1523,6 +1524,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (!this.actuallyHurt(world, source, (float) event.getFinalDamage(), event)) { - return false; - } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. - this.lastHurt = amount; - this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks - // this.actuallyHurt(worldserver, damagesource, f); -@@ -2488,12 +2490,12 @@ public abstract class LivingEntity extends Entity implements Attackable { - - return true; - } else { -- return originalDamage > 0; -+ return true; // Paper - return false ONLY if event was cancelled - } - // CraftBukkit end - } - } -- return false; // CraftBukkit -+ return true; // CraftBukkit // Paper - return false ONLY if event was cancelled - } - - public CombatTracker getCombatTracker() { diff --git a/patches/server/0950-improve-checking-handled-tags-in-itemmeta.patch b/patches/server/0950-improve-checking-handled-tags-in-itemmeta.patch new file mode 100644 index 0000000000..8d257c881d --- /dev/null +++ b/patches/server/0950-improve-checking-handled-tags-in-itemmeta.patch @@ -0,0 +1,887 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 10 Jul 2023 16:10:15 -0700 +Subject: [PATCH] improve checking handled tags in itemmeta + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java +index d29f4dd9808e2001c79535d663ca77d6840f6092..1fd6e5a1ada184f9b399b7c41718ffd7db086d91 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java +@@ -40,120 +40,120 @@ import org.bukkit.inventory.meta.TropicalFishBucketMeta; + + public final class CraftItemMetas { + +- public record ItemMetaData(Class metaClass, Function fromItemStack, ++ public record ItemMetaData(Class metaClass, BiFunction>, I> fromItemStack, + BiFunction, CraftMetaItem, I> fromItemMeta) { + } + + private static final ItemMetaData EMPTY_META_DATA = new ItemMetaData<>(ItemMeta.class, +- item -> null, ++ (item, extras) -> null, + (type, meta) -> null); + + private static final ItemMetaData ITEM_META_DATA = new ItemMetaData<>(ItemMeta.class, +- item -> new CraftMetaItem(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaItem(item.getComponentsPatch(), extras), + (type, meta) -> new CraftMetaItem(meta)); + + private static final ItemMetaData SIGNED_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, +- item -> new CraftMetaBookSigned(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBookSigned(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaBookSigned signed ? signed : new CraftMetaBookSigned(meta)); + + private static final ItemMetaData WRITABLE_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, +- item -> new CraftMetaBook(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBook(item.getComponentsPatch(), extras), + (type, meta) -> meta != null && meta.getClass().equals(CraftMetaBook.class) ? (BookMeta) meta : new CraftMetaBook(meta)); + + private static final ItemMetaData SKULL_META_DATA = new ItemMetaData<>(SkullMeta.class, +- item -> new CraftMetaSkull(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaSkull(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaSkull skull ? skull : new CraftMetaSkull(meta)); + + private static final ItemMetaData ARMOR_META_DATA = new ItemMetaData<>(ArmorMeta.class, +- item -> new CraftMetaArmor(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaArmor(item.getComponentsPatch(), extras), + (type, meta) -> meta != null && meta.getClass().equals(CraftMetaArmor.class) ? (ArmorMeta) meta : new CraftMetaArmor(meta)); + + private static final ItemMetaData COLORABLE_ARMOR_META_DATA = new ItemMetaData<>(ColorableArmorMeta.class, +- item -> new CraftMetaColorableArmor(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaColorableArmor(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof ColorableArmorMeta colorable ? colorable : new CraftMetaColorableArmor(meta)); + + private static final ItemMetaData LEATHER_ARMOR_META_DATA = new ItemMetaData<>(LeatherArmorMeta.class, +- item -> new CraftMetaLeatherArmor(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaLeatherArmor(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaLeatherArmor leather ? leather : new CraftMetaLeatherArmor(meta)); + + private static final ItemMetaData POTION_META_DATA = new ItemMetaData<>(PotionMeta.class, +- item -> new CraftMetaPotion(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaPotion(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaPotion potion ? potion : new CraftMetaPotion(meta)); + + private static final ItemMetaData MAP_META_DATA = new ItemMetaData<>(MapMeta.class, +- item -> new CraftMetaMap(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaMap(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaMap map ? map : new CraftMetaMap(meta)); + + private static final ItemMetaData FIREWORK_META_DATA = new ItemMetaData<>(FireworkMeta.class, +- item -> new CraftMetaFirework(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaFirework(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaFirework firework ? firework : new CraftMetaFirework(meta)); + + private static final ItemMetaData CHARGE_META_DATA = new ItemMetaData<>(FireworkEffectMeta.class, +- item -> new CraftMetaCharge(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaCharge(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaCharge charge ? charge : new CraftMetaCharge(meta)); + + private static final ItemMetaData ENCHANTED_BOOK_META_DATA = new ItemMetaData<>(EnchantmentStorageMeta.class, +- item -> new CraftMetaEnchantedBook(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaEnchantedBook(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaEnchantedBook enchantedBook ? enchantedBook : new CraftMetaEnchantedBook(meta)); + + private static final ItemMetaData BANNER_META_DATA = new ItemMetaData<>(BannerMeta.class, +- item -> new CraftMetaBanner(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBanner(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaBanner banner ? banner : new CraftMetaBanner(meta)); + + private static final ItemMetaData SPAWN_EGG_META_DATA = new ItemMetaData<>(SpawnEggMeta.class, +- item -> new CraftMetaSpawnEgg(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaSpawnEgg(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaSpawnEgg spawnEgg ? spawnEgg : new CraftMetaSpawnEgg(meta)); + + private static final ItemMetaData ARMOR_STAND_META_DATA = new ItemMetaData<>(ArmorStandMeta.class, // paper +- item -> new CraftMetaArmorStand(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaArmorStand(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaArmorStand armorStand ? armorStand : new CraftMetaArmorStand(meta)); + + private static final ItemMetaData KNOWLEDGE_BOOK_META_DATA = new ItemMetaData<>(KnowledgeBookMeta.class, +- item -> new CraftMetaKnowledgeBook(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaKnowledgeBook(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaKnowledgeBook knowledgeBook ? knowledgeBook : new CraftMetaKnowledgeBook(meta)); + + private static final ItemMetaData BLOCK_STATE_META_DATA = new ItemMetaData<>(BlockStateMeta.class, +- item -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem())), ++ (item, extras) -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem()), extras), + (type, meta) -> new CraftMetaBlockState(meta, type.asMaterial())); + + private static final ItemMetaData SHIELD_META_DATA = new ItemMetaData<>(ShieldMeta.class, +- item -> new CraftMetaShield(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaShield(item.getComponentsPatch(), extras), + (type, meta) -> new CraftMetaShield(meta)); + + private static final ItemMetaData TROPICAL_FISH_BUCKET_META_DATA = new ItemMetaData<>(TropicalFishBucketMeta.class, +- item -> new CraftMetaTropicalFishBucket(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaTropicalFishBucket(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaTropicalFishBucket tropicalFishBucket ? tropicalFishBucket : new CraftMetaTropicalFishBucket(meta)); + + private static final ItemMetaData AXOLOTL_BUCKET_META_DATA = new ItemMetaData<>(AxolotlBucketMeta.class, +- item -> new CraftMetaAxolotlBucket(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaAxolotlBucket(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaAxolotlBucket axolotlBucket ? axolotlBucket : new CraftMetaAxolotlBucket(meta)); + + private static final ItemMetaData CROSSBOW_META_DATA = new ItemMetaData<>(CrossbowMeta.class, +- item -> new CraftMetaCrossbow(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaCrossbow(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaCrossbow crossbow ? crossbow : new CraftMetaCrossbow(meta)); + + private static final ItemMetaData SUSPICIOUS_STEW_META_DATA = new ItemMetaData<>(SuspiciousStewMeta.class, +- item -> new CraftMetaSuspiciousStew(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaSuspiciousStew(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaSuspiciousStew suspiciousStew ? suspiciousStew : new CraftMetaSuspiciousStew(meta)); + + private static final ItemMetaData ENTITY_TAG_META_DATA = new ItemMetaData<>(ItemMeta.class, +- item -> new CraftMetaEntityTag(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaEntityTag(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaEntityTag entityTag ? entityTag : new CraftMetaEntityTag(meta)); + + private static final ItemMetaData COMPASS_META_DATA = new ItemMetaData<>(CompassMeta.class, +- item -> new CraftMetaCompass(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaCompass(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaCompass compass ? compass : new CraftMetaCompass(meta)); + + private static final ItemMetaData BUNDLE_META_DATA = new ItemMetaData<>(BundleMeta.class, +- item -> new CraftMetaBundle(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBundle(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaBundle bundle ? bundle : new CraftMetaBundle(meta)); + + private static final ItemMetaData MUSIC_INSTRUMENT_META_DATA = new ItemMetaData<>(MusicInstrumentMeta.class, +- item -> new CraftMetaMusicInstrument(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaMusicInstrument(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaMusicInstrument musicInstrument ? musicInstrument : new CraftMetaMusicInstrument(meta)); + + private static final ItemMetaData OMINOUS_BOTTLE_META_DATA = new ItemMetaData<>(OminousBottleMeta.class, +- item -> new CraftMetaOminousBottle(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaOminousBottle(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaOminousBottle musicInstrument ? musicInstrument : new CraftMetaOminousBottle(meta)); + + // We use if instead of a set, since the result gets cached in CraftItemType, +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 7228d43d331de16cbaa0e97c7e3fa45c0bc89558..dfdabf86433d323966a748baef769cf0462d3f38 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -173,10 +173,11 @@ public final class CraftItemStack extends ItemStack { + } else if (this.handle == null) { + this.handle = new net.minecraft.world.item.ItemStack(CraftItemType.bukkitToMinecraft(type), 1); + } else { ++ final Material oldType = CraftMagicNumbers.getMaterial(this.handle.getItem()); // Paper + this.handle.setItem(CraftItemType.bukkitToMinecraft(type)); + if (this.hasItemMeta()) { + // This will create the appropriate item meta, which will contain all the data we intend to keep +- CraftItemStack.setItemMeta(this.handle, CraftItemStack.getItemMeta(this.handle)); ++ this.adjustTagForItemMeta(oldType); // Paper + } + } + this.setData(null); +@@ -337,6 +338,19 @@ public final class CraftItemStack extends ItemStack { + public ItemMeta getItemMeta() { + return CraftItemStack.getItemMeta(this.handle); + } ++ // Paper start - improve handled tags on type change ++ public void adjustTagForItemMeta(final Material oldType) { ++ final CraftMetaItem oldMeta = (CraftMetaItem) CraftItemFactory.instance().getItemMeta(oldType); ++ final ItemMeta newMeta; ++ if (oldMeta == null) { ++ newMeta = getItemMeta(this.handle); ++ } else { ++ final java.util.Set> extraHandledDcts = new java.util.HashSet<>(CraftMetaItem.getTopLevelHandledDcts(oldMeta.getClass())); ++ newMeta = getItemMeta(this.handle, CraftItemType.minecraftToBukkitNew(this.handle.getItem()), extraHandledDcts); ++ } ++ this.setItemMeta(newMeta); ++ } ++ // Paper end - improve handled tags on type change + // Paper start + public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { + final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); +@@ -349,12 +363,17 @@ public final class CraftItemStack extends ItemStack { + } + public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType) { + // Paper end ++ // Paper start - handled tags on type change ++ return getItemMeta(item, metaForType, null); ++ } ++ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType, final java.util.Set> extraHandledDcts) { ++ // Paper end - handled tags on type change + if (!CraftItemStack.hasItemMeta(item)) { + return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item)); + } + +- if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item); } // Paper +- return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item); ++ if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item, extraHandledDcts); } // Paper ++ return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item, extraHandledDcts); // Paper + } + + static Material getType(net.minecraft.world.item.ItemStack item) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +index 6d76cc1db3ac3f1ae74c13511937fb86082a0b3d..f4a6ee6dfcb2d516a9a1a9c81494b50a629110e4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +@@ -114,8 +114,8 @@ public class CraftItemType implements ItemType.Typed, Han + return this.item; + } + +- public M getItemMeta(net.minecraft.world.item.ItemStack itemStack) { +- return this.itemMetaData.get().fromItemStack().apply(itemStack); ++ public M getItemMeta(net.minecraft.world.item.ItemStack itemStack, final java.util.Set> extraHandledDcts) { ++ return this.itemMetaData.get().fromItemStack().apply(itemStack, extraHandledDcts); + } + + public M getItemMeta(ItemMeta itemMeta) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +index 0d3b1692af010bfd7ea83e22e9571dc954906f71..e83a662f82b144b11a003a682633cd0ee797fd19 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +@@ -34,8 +34,8 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { + } + } + +- CraftMetaArmor(DataComponentPatch tag) { +- super(tag); ++ CraftMetaArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaArmor.TRIM).ifPresent((trimCompound) -> { + TrimMaterial trimMaterial = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL, trimCompound.material()).orElse(null); // Paper - fix upstream not being correct +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java +index ecce5d0da946ca279c5608068442cc53437dd2a5..00b5c4ab6111f980db1b9e99f901667741266440 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java +@@ -35,8 +35,8 @@ public class CraftMetaArmorStand extends CraftMetaItem implements com.destroysto + this.entityTag = armorStand.entityTag; + } + +- CraftMetaArmorStand(DataComponentPatch tag) { +- super(tag); ++ CraftMetaArmorStand(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaArmorStand.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java +index c4beb94d8e5448e69f31f30299448f344b5d8f59..169fefb64e1af444f7c2efb1234cb6e7779fb717 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java +@@ -36,8 +36,8 @@ public class CraftMetaAxolotlBucket extends CraftMetaItem implements AxolotlBuck + this.bucketEntityTag = bucket.bucketEntityTag; + } + +- CraftMetaAxolotlBucket(DataComponentPatch tag) { +- super(tag); ++ CraftMetaAxolotlBucket(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaAxolotlBucket.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +index eb44c19f6af624df458981e46c73a64358d6e1ce..d0a8cd89da3b8d87248494056470c306f8fb5ae8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +@@ -34,8 +34,8 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { + this.patterns = new ArrayList(banner.patterns); + } + +- CraftMetaBanner(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBanner(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBanner.PATTERNS).ifPresent((entityTag) -> { + List patterns = entityTag.layers(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +index 3985e5b4e2d65faa8eaea1d4a2acc6fb1e64f959..413e41f113226b8a2e9b30bb519076d78e451fa0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +@@ -73,8 +73,8 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + this.position = te.position; + } + +- CraftMetaBlockState(DataComponentPatch tag, Material material) { +- super(tag); ++ CraftMetaBlockState(DataComponentPatch tag, Material material, final Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + this.material = material; + + getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((blockTag) -> { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +index 32e5188442551b3e72e1d4826d836d622d0e438a..257c835bc280eee9ee73ae75b5249bb568a687d0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +@@ -64,8 +64,8 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta, WritableBo + } + } + +- CraftMetaBook(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBook.BOOK_CONTENT).ifPresent((writable) -> { + List> pages = writable.pages(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java +index fd3b12477c30d1eabdbe57ea779027931e9dd957..cbb3d80cc7cd81b2505dff999a0baede737165f7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java +@@ -78,8 +78,8 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta { + } + } + +- CraftMetaBookSigned(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBookSigned(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBookSigned.BOOK_CONTENT).ifPresent((written) -> { + this.title = written.title().raw(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java +index 30533ce683e0471742b27d1d31df20def8ea169c..2736a87a6c481da0575e6e29ea08faa539c24378 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java +@@ -34,8 +34,8 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { + } + } + +- CraftMetaBundle(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBundle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBundle.ITEMS).ifPresent((bundle) -> { + bundle.items().forEach((item) -> { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java +index 72340e7269a5464d72abe8370c8113f3de9573d2..56c6784e29cecf8655282235959de536d07c1e08 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java +@@ -29,8 +29,8 @@ class CraftMetaCharge extends CraftMetaItem implements FireworkEffectMeta { + this.setEffect(SerializableMeta.getObject(FireworkEffect.class, map, CraftMetaCharge.EXPLOSION.BUKKIT, true)); + } + +- CraftMetaCharge(DataComponentPatch tag) { +- super(tag); ++ CraftMetaCharge(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaCharge.EXPLOSION).ifPresent((f) -> { + try { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +index 366fec1aee66de4031727a1383acebd319eeef88..6517ec4933b0eae761fceb117ea1db175755d0b1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +@@ -18,8 +18,8 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable + CraftMetaLeatherArmor.readColor(this, meta); + } + +- CraftMetaColorableArmor(DataComponentPatch tag) { +- super(tag); ++ CraftMetaColorableArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + CraftMetaLeatherArmor.readColor(this, tag); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java +index 607e23040383576b2805c25947a69f6efe6d2c88..69a112b3a9726966aecbe687d905fd1a11cfa1e3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java +@@ -50,8 +50,8 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + this.tracked = compassMeta.tracked; + } + +- CraftMetaCompass(DataComponentPatch tag) { +- super(tag); ++ CraftMetaCompass(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaCompass.LODESTONE_TARGET).ifPresent((lodestoneTarget) -> { + lodestoneTarget.target().ifPresent((target) -> { + this.lodestoneWorld = target.dimension(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java +index c278af519308c84ad76fc2312046980c01c528ba..0807c2172c5a4bee675cef265a45a9350e98b880 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java +@@ -36,8 +36,8 @@ public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta { + } + } + +- CraftMetaCrossbow(DataComponentPatch tag) { +- super(tag); ++ CraftMetaCrossbow(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaCrossbow.CHARGED_PROJECTILES).ifPresent((p) -> { + List list = p.getItems(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +index 19af55ec2bf62b70bd3be44f499b32f5efe71ab1..c93f769ee6c55022653696da45de568fcf7589fe 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +@@ -32,8 +32,8 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage + } + } + +- CraftMetaEnchantedBook(DataComponentPatch tag) { +- super(tag); ++ CraftMetaEnchantedBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { + this.enchantments = buildEnchantments(itemEnchantments); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +index 3ff0340c40e9dc9a6e690de15ccade7a0c4e8f02..3f6c5cbbf63631e4b72dc43558651ea94f31ca78 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +@@ -39,8 +39,8 @@ public class CraftMetaEntityTag extends CraftMetaItem { + this.entityTag = entity.entityTag; + } + +- CraftMetaEntityTag(DataComponentPatch tag) { +- super(tag); ++ CraftMetaEntityTag(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaEntityTag.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +index 4941e0afff8df5f10f06c715b54bf58eb86051c5..566d893a413fd04b99e83dc2da8fe958a48492a8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +@@ -60,8 +60,8 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + } + } + +- CraftMetaFirework(DataComponentPatch tag) { +- super(tag); ++ CraftMetaFirework(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaFirework.FIREWORKS).ifPresent((fireworks) -> { + this.power = fireworks.flightDuration(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 6b3eed94c26bc16177f9b9fadd140f9a89163af2..13b19adc21ece31476b2980c5bc01a50f15df634 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -389,7 +389,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + // Paper end + } + +- CraftMetaItem(DataComponentPatch tag) { ++ CraftMetaItem(DataComponentPatch tag, Set> extraHandledTags) { // Paper - improve handled tags on type changes + CraftMetaItem.getOrEmpty(tag, CraftMetaItem.NAME).ifPresent((component) -> { + this.displayName = component; + }); +@@ -521,9 +521,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + }); + // Paper end - fix ItemFlags + ++ // Paper start - improve checking handled data component types ++ Set> handledTags = getTopLevelHandledDcts(this.getClass()); ++ if (extraHandledTags != null) { ++ extraHandledTags.addAll(handledTags); ++ handledTags = extraHandledTags; ++ } ++ // Paper end - improve checking handled data component types + Set, Optional>> keys = tag.entrySet(); + for (Map.Entry, Optional> key : keys) { +- if (!CraftMetaItem.getHandledTags().contains(key.getKey())) { ++ if (!handledTags.contains(key.getKey())) { // Paper - improve checking handled data component types + key.getValue().ifPresent((value) -> { + this.unhandledTags.set((DataComponentType) key.getKey(), value); + }); +@@ -2351,75 +2358,83 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.version = version; + } + +- public static Set getHandledTags() { +- synchronized (CraftMetaItem.HANDLED_TAGS) { +- if (CraftMetaItem.HANDLED_TAGS.isEmpty()) { +- CraftMetaItem.HANDLED_TAGS.addAll(Arrays.asList( +- CraftMetaItem.NAME.TYPE, +- CraftMetaItem.ITEM_NAME.TYPE, +- CraftMetaItem.LORE.TYPE, +- CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, +- CraftMetaItem.ENCHANTABLE.TYPE, +- CraftMetaItem.BLOCK_DATA.TYPE, +- CraftMetaItem.REPAIR.TYPE, +- CraftMetaItem.ENCHANTMENTS.TYPE, +- CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, +- CraftMetaItem.HIDE_TOOLTIP.TYPE, +- CraftMetaItem.TOOLTIP_STYLE.TYPE, +- CraftMetaItem.ITEM_MODEL.TYPE, +- CraftMetaItem.UNBREAKABLE.TYPE, +- CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, +- CraftMetaItem.GLIDER.TYPE, +- CraftMetaItem.DAMAGE_RESISTANT.TYPE, +- CraftMetaItem.MAX_STACK_SIZE.TYPE, +- CraftMetaItem.RARITY.TYPE, +- CraftMetaItem.USE_REMAINDER.TYPE, +- CraftMetaItem.USE_COOLDOWN.TYPE, +- CraftMetaItem.FOOD.TYPE, +- CraftMetaItem.TOOL.TYPE, +- CraftMetaItem.EQUIPPABLE.TYPE, +- CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, +- CraftMetaItem.DAMAGE.TYPE, +- CraftMetaItem.MAX_DAMAGE.TYPE, +- CraftMetaItem.CUSTOM_DATA.TYPE, +- CraftMetaItem.ATTRIBUTES.TYPE, +- CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper +- CraftMetaItem.CAN_BREAK.TYPE, // Paper +- CraftMetaArmor.TRIM.TYPE, +- CraftMetaArmorStand.ENTITY_TAG.TYPE, +- CraftMetaBanner.PATTERNS.TYPE, +- CraftMetaEntityTag.ENTITY_TAG.TYPE, +- CraftMetaLeatherArmor.COLOR.TYPE, +- CraftMetaMap.MAP_POST_PROCESSING.TYPE, +- CraftMetaMap.MAP_COLOR.TYPE, +- CraftMetaMap.MAP_ID.TYPE, +- CraftMetaPotion.POTION_CONTENTS.TYPE, +- CraftMetaShield.BASE_COLOR.TYPE, +- CraftMetaSkull.SKULL_PROFILE.TYPE, +- CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE, +- CraftMetaSpawnEgg.ENTITY_TAG.TYPE, +- CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE, +- CraftMetaBook.BOOK_CONTENT.TYPE, +- CraftMetaBookSigned.BOOK_CONTENT.TYPE, +- CraftMetaFirework.FIREWORKS.TYPE, +- CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE, +- CraftMetaCharge.EXPLOSION.TYPE, +- CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE, +- CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, +- CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE, +- CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, +- CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE, +- CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE, +- CraftMetaSuspiciousStew.EFFECTS.TYPE, +- CraftMetaCompass.LODESTONE_TARGET.TYPE, +- CraftMetaBundle.ITEMS.TYPE, +- CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE, +- CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE +- )); +- } +- return CraftMetaItem.HANDLED_TAGS; ++ // Paper start - improve checking handled tags ++ @org.jetbrains.annotations.VisibleForTesting ++ public static final Map, Set>> HANDLED_DCTS_PER_TYPE = new HashMap<>(); ++ private static final Set> DEFAULT_HANDLED_DCTS = Set.of( ++ CraftMetaItem.NAME.TYPE, ++ CraftMetaItem.ITEM_NAME.TYPE, ++ CraftMetaItem.LORE.TYPE, ++ CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, ++ CraftMetaItem.ENCHANTABLE.TYPE, ++ CraftMetaItem.BLOCK_DATA.TYPE, ++ CraftMetaItem.REPAIR.TYPE, ++ CraftMetaItem.ENCHANTMENTS.TYPE, ++ CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, ++ CraftMetaItem.HIDE_TOOLTIP.TYPE, ++ CraftMetaItem.TOOLTIP_STYLE.TYPE, ++ CraftMetaItem.ITEM_MODEL.TYPE, ++ CraftMetaItem.UNBREAKABLE.TYPE, ++ CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, ++ CraftMetaItem.GLIDER.TYPE, ++ CraftMetaItem.DAMAGE_RESISTANT.TYPE, ++ CraftMetaItem.MAX_STACK_SIZE.TYPE, ++ CraftMetaItem.RARITY.TYPE, ++ CraftMetaItem.USE_REMAINDER.TYPE, ++ CraftMetaItem.USE_COOLDOWN.TYPE, ++ CraftMetaItem.FOOD.TYPE, ++ CraftMetaItem.TOOL.TYPE, ++ CraftMetaItem.EQUIPPABLE.TYPE, ++ CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, ++ CraftMetaItem.DAMAGE.TYPE, ++ CraftMetaItem.MAX_DAMAGE.TYPE, ++ CraftMetaItem.CUSTOM_DATA.TYPE, ++ CraftMetaItem.ATTRIBUTES.TYPE, ++ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper ++ CraftMetaItem.CAN_BREAK.TYPE // Paper ++ ); ++ public static Set> getTopLevelHandledDcts(final Class clazz) { ++ synchronized (HANDLED_DCTS_PER_TYPE) { ++ if (HANDLED_DCTS_PER_TYPE.isEmpty()) { ++ final Map, Set>> map = new HashMap<>(); ++ map.put(CraftMetaArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE)); ++ map.put(CraftMetaArmorStand.class, Set.of(CraftMetaArmorStand.ENTITY_TAG.TYPE)); ++ map.put(CraftMetaAxolotlBucket.class, Set.of(CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE)); ++ map.put(CraftMetaBanner.class, Set.of(CraftMetaBanner.PATTERNS.TYPE)); // banner uses same tag as block state ++ map.put(CraftMetaShield.class, Set.of(CraftMetaShield.BASE_COLOR.TYPE, CraftMetaBanner.PATTERNS.TYPE)); ++ map.put(CraftMetaBlockState.class, Set.of(CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE)); ++ map.put(CraftMetaBook.class, Set.of(CraftMetaBook.BOOK_CONTENT.TYPE)); ++ map.put(CraftMetaBookSigned.class, Set.of(CraftMetaBookSigned.BOOK_CONTENT.TYPE)); ++ map.put(CraftMetaBundle.class, Set.of(CraftMetaBundle.ITEMS.TYPE)); ++ map.put(CraftMetaCharge.class, Set.of(CraftMetaCharge.EXPLOSION.TYPE)); ++ map.put(CraftMetaColorableArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE, CraftMetaLeatherArmor.COLOR.TYPE)); ++ map.put(CraftMetaCompass.class, Set.of(CraftMetaCompass.LODESTONE_TARGET.TYPE)); ++ map.put(CraftMetaCrossbow.class, Set.of(CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE)); ++ map.put(CraftMetaEnchantedBook.class, Set.of(CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE)); ++ map.put(CraftMetaEntityTag.class, Set.of(CraftMetaEntityTag.ENTITY_TAG.TYPE)); ++ map.put(CraftMetaFirework.class, Set.of(CraftMetaFirework.FIREWORKS.TYPE)); ++ map.put(CraftMetaKnowledgeBook.class, Set.of(CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE)); ++ map.put(CraftMetaLeatherArmor.class, Set.of(CraftMetaLeatherArmor.COLOR.TYPE)); ++ map.put(CraftMetaMap.class, Set.of(CraftMetaMap.MAP_COLOR.TYPE, CraftMetaMap.MAP_POST_PROCESSING.TYPE, CraftMetaMap.MAP_ID.TYPE)); ++ map.put(CraftMetaMusicInstrument.class, Set.of(CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE)); ++ map.put(CraftMetaOminousBottle.class, Set.of(CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE)); ++ map.put(CraftMetaPotion.class, Set.of(CraftMetaPotion.POTION_CONTENTS.TYPE)); ++ map.put(CraftMetaSkull.class, Set.of(CraftMetaSkull.SKULL_PROFILE.TYPE, CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE)); ++ map.put(CraftMetaSpawnEgg.class, Set.of(CraftMetaSpawnEgg.ENTITY_TAG.TYPE)); ++ map.put(CraftMetaSuspiciousStew.class, Set.of(CraftMetaSuspiciousStew.EFFECTS.TYPE)); ++ map.put(CraftMetaTropicalFishBucket.class, Set.of(CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE)); ++ ++ for (final Map.Entry, Set>> entry : map.entrySet()) { ++ final ArrayList> topLevelTags = new ArrayList<>(entry.getValue()); ++ // add tags common to CraftMetaItem to all ++ topLevelTags.addAll(DEFAULT_HANDLED_DCTS); ++ HANDLED_DCTS_PER_TYPE.put(entry.getKey(), Set.copyOf(topLevelTags)); ++ } ++ } ++ return HANDLED_DCTS_PER_TYPE.getOrDefault(clazz, DEFAULT_HANDLED_DCTS); + } + } ++ // Paper end - improve checking handled data component types + + protected static Optional getOrEmpty(DataComponentPatch tag, ItemMetaKeyType type) { + Optional result = tag.get(type.TYPE); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java +index 68c0a6d5e06a44ddddddb9cbe093ed6814380444..4dc7adb626ccb74b7e3a60c5a7250d0dc9703997 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java +@@ -32,8 +32,8 @@ public class CraftMetaKnowledgeBook extends CraftMetaItem implements KnowledgeBo + } + } + +- CraftMetaKnowledgeBook(DataComponentPatch tag) { +- super(tag); ++ CraftMetaKnowledgeBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaKnowledgeBook.BOOK_RECIPES).ifPresent((pages) -> { + for (int i = 0; i < pages.size(); i++) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +index 75a8ad69902103a2e33a457c3225a33860d075ed..e8c950aa74d31bf7a9128f4acc4bccee26bbcd7f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +@@ -25,8 +25,8 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + CraftMetaLeatherArmor.readColor(this, meta); + } + +- CraftMetaLeatherArmor(DataComponentPatch tag) { +- super(tag); ++ CraftMetaLeatherArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + CraftMetaLeatherArmor.readColor(this, tag); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java +index 08e18dcabbf52aae5c3843d49a72d1d52baa729b..149356981e586e4f67d4543d3df94a2ea99333fc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java +@@ -44,8 +44,8 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { + this.color = map.color; + } + +- CraftMetaMap(DataComponentPatch tag) { +- super(tag); ++ CraftMetaMap(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaMap.MAP_ID).ifPresent((mapId) -> { + this.mapId = mapId.id(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +index 76a3e4893cbdba903a712d6db1d30b9c644795be..a80b9b142ca99c7c0257b1bdeb059dce5f92ae93 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +@@ -26,8 +26,8 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst + } + } + +- CraftMetaMusicInstrument(DataComponentPatch tag) { +- super(tag); ++ CraftMetaMusicInstrument(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT).ifPresent((instrument) -> { + this.instrument = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.INSTRUMENT, instrument).orElse(null); // Paper - fix upstream not handling inlined instrument +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java +index ed272c7eb435677de5f6b106a6012c472decbb62..b118d8ecb505d187c02bb158f14df333f487a87f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java +@@ -24,8 +24,8 @@ public class CraftMetaOminousBottle extends CraftMetaItem implements OminousBott + this.ominousBottleAmplifier = bottleMeta.ominousBottleAmplifier; + } + +- CraftMetaOminousBottle(DataComponentPatch tag) { +- super(tag); ++ CraftMetaOminousBottle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER).ifPresent((amplifier) -> { + this.ominousBottleAmplifier = amplifier.value(); + }); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +index 533c600d632eb733c121f5d8189142726b091713..6f0eebcaffa20337cf5a7f8485f891c690d948ae 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +@@ -54,8 +54,8 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + } + } + +- CraftMetaPotion(DataComponentPatch tag) { +- super(tag); ++ CraftMetaPotion(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaPotion.POTION_CONTENTS).ifPresent((potionContents) -> { + potionContents.potion().ifPresent((potion) -> { + this.type = CraftPotionType.minecraftHolderToBukkit(potion); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +index bcd6cc29e4e621805cbd923d747f652ced240c6d..967d8940aec0065bce496d5d7a8c73de5733bd2c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +@@ -42,8 +42,8 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + } + } + +- CraftMetaShield(DataComponentPatch tag) { +- super(tag); ++ CraftMetaShield(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper - improve checking handled tags in item meta ++ super(tag, extraHandledDcts); // Paper - improve checking handled tags in item meta + + getOrEmpty(tag, CraftMetaShield.BASE_COLOR).ifPresent((color) -> { + this.banner = CraftMetaShield.getBlockState(DyeColor.getByWoolData((byte) color.getId())); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +index ca714e165e453d1072d083441d8b985290ada75a..302906467b12189e21633369c005736863f46dd5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +@@ -48,8 +48,8 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { + this.noteBlockSound = skullMeta.noteBlockSound; + } + +- CraftMetaSkull(DataComponentPatch tag) { +- super(tag); ++ CraftMetaSkull(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaSkull.SKULL_PROFILE).ifPresent(this::setProfile); + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +index 6c2c3b514be0dab47f3e44f65bdc6a3574e59b7c..8ddf091b3ff1262b6c97e8fe72e0a80db5e1037d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +@@ -33,8 +33,8 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { + this.entityTag = egg.entityTag; + } + +- CraftMetaSpawnEgg(DataComponentPatch tag) { +- super(tag); ++ CraftMetaSpawnEgg(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaSpawnEgg.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java +index 248efddbad2bfee4f9aa33ec738b5353054eda61..7a43e326e51300306b9c5c23a16ffae92030bd2b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java +@@ -33,8 +33,8 @@ public class CraftMetaSuspiciousStew extends CraftMetaItem implements Suspicious + } + } + +- CraftMetaSuspiciousStew(DataComponentPatch tag) { +- super(tag); ++ CraftMetaSuspiciousStew(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaSuspiciousStew.EFFECTS).ifPresent((suspiciousStewEffects) -> { + List list = suspiciousStewEffects.effects(); + int length = list.size(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +index a514fe98d3d2b65d2cfd029079c69189bcb99c01..17705059b81942e4df43a4a5180092e09c985ade 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +@@ -38,8 +38,8 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB + this.bucketEntityTag = bucket.bucketEntityTag; + } + +- CraftMetaTropicalFishBucket(DataComponentPatch tag) { +- super(tag); ++ CraftMetaTropicalFishBucket(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaTropicalFishBucket.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java +index 91cfa32272770cdfe56d97154ea9db4e2ed8a328..9cc1ef5c9221dd7d2069b280f0c91ce9439a995a 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java +@@ -97,7 +97,7 @@ public class DeprecatedItemMetaCustomValueTest { + CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); + itemMeta.applyToItem(compound); + +- assertEquals(itemMeta, new CraftMetaItem(compound.build())); ++ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper + } + + @Test +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df20446af3d43c624278d1a25f31f702677c8d96 +--- /dev/null ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java +@@ -0,0 +1,33 @@ ++package org.bukkit.craftbukkit.inventory; ++ ++import io.github.classgraph.ClassGraph; ++import io.github.classgraph.ClassInfo; ++import io.github.classgraph.ClassInfoList; ++import io.github.classgraph.ScanResult; ++import org.bukkit.support.environment.AllFeatures; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertFalse; ++import static org.junit.jupiter.api.Assertions.assertTrue; ++ ++// in cb package because of package-private stuff ++@AllFeatures ++class MetaHandledTagsTest { ++ ++ @Test ++ public void checkAllMetasHaveHandledTags() { ++ try (final ScanResult result = new ClassGraph() ++ .whitelistPackages("org.bukkit.craftbukkit.inventory") ++ .enableClassInfo().scan()) { ++ final ClassInfoList subclasses = result.getSubclasses(CraftMetaItem.class.getName()); ++ assertFalse(subclasses.isEmpty(), "found 0 sub types"); ++ for (final ClassInfo subclass : subclasses) { ++ final Class clazz = subclass.loadClass(CraftMetaItem.class); ++ CraftMetaItem.getTopLevelHandledDcts(clazz); // load into map ++ assertTrue(CraftMetaItem.HANDLED_DCTS_PER_TYPE.containsKey(clazz), subclass.getName() + " not found in handled tags map"); ++ } ++ } catch (Exception e) { ++ throw new RuntimeException(e); ++ } ++ } ++} +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java +index 5b16e6f5e5517eed218e4b60ecd75f8b80712e89..130c4500a5e854480962c8f720b1df4c67d43c33 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java +@@ -131,7 +131,7 @@ public class PersistentDataContainerTest { + CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); + itemMeta.applyToItem(compound); + +- assertEquals(itemMeta, new CraftMetaItem(compound.build())); ++ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper + } + + @Test +@@ -464,7 +464,7 @@ public class PersistentDataContainerTest { + + @Test + public void testEmptyListApplicationToAnyType() throws IOException { +- final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY); ++ final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY, null); // Paper + final PersistentDataContainer container = craftItem.getPersistentDataContainer(); + + container.set(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings(), List.of()); +@@ -477,7 +477,7 @@ public class PersistentDataContainerTest { + final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator(); + craftItem.applyToItem(storage); + +- final CraftMetaItem readItem = new CraftMetaItem(storage.build()); ++ final CraftMetaItem readItem = new CraftMetaItem(storage.build(), null); // Paper + final PersistentDataContainer readContainer = readItem.getPersistentDataContainer(); + + assertTrue(readContainer.has(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings())); diff --git a/patches/server/0951-Expose-hasColor-to-leather-armor.patch b/patches/server/0951-Expose-hasColor-to-leather-armor.patch new file mode 100644 index 0000000000..9166ad6261 --- /dev/null +++ b/patches/server/0951-Expose-hasColor-to-leather-armor.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 1 May 2024 10:58:50 +0300 +Subject: [PATCH] Expose #hasColor to leather armor + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +index 6517ec4933b0eae761fceb117ea1db175755d0b1..dc6398cfbd6e749733c3a681e1eb8ce15c3b2c5e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +@@ -100,4 +100,11 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable + } + return original != hash ? CraftMetaColorableArmor.class.hashCode() ^ hash : hash; + } ++ ++ // Paper start - Expose #hasColor to leather armor ++ @Override ++ public boolean isDyed() { ++ return hasColor(); ++ } ++ // Paper end - Expose #hasColor to leather armor + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +index e8c950aa74d31bf7a9128f4acc4bccee26bbcd7f..e76749bffaf5a0bbd3a8d35f882edcc3598351b9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +@@ -156,4 +156,11 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + builder.put(CraftMetaLeatherArmor.COLOR.BUKKIT, meta.getColor()); + } + } ++ ++ // Paper start - Expose #hasColor to leather armor ++ @Override ++ public boolean isDyed() { ++ return hasColor(); ++ } ++ // Paper end - Expose #hasColor to leather armor + } diff --git a/patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch b/patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch deleted file mode 100644 index 8d257c881d..0000000000 --- a/patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch +++ /dev/null @@ -1,887 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 10 Jul 2023 16:10:15 -0700 -Subject: [PATCH] improve checking handled tags in itemmeta - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -index d29f4dd9808e2001c79535d663ca77d6840f6092..1fd6e5a1ada184f9b399b7c41718ffd7db086d91 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -@@ -40,120 +40,120 @@ import org.bukkit.inventory.meta.TropicalFishBucketMeta; - - public final class CraftItemMetas { - -- public record ItemMetaData(Class metaClass, Function fromItemStack, -+ public record ItemMetaData(Class metaClass, BiFunction>, I> fromItemStack, - BiFunction, CraftMetaItem, I> fromItemMeta) { - } - - private static final ItemMetaData EMPTY_META_DATA = new ItemMetaData<>(ItemMeta.class, -- item -> null, -+ (item, extras) -> null, - (type, meta) -> null); - - private static final ItemMetaData ITEM_META_DATA = new ItemMetaData<>(ItemMeta.class, -- item -> new CraftMetaItem(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaItem(item.getComponentsPatch(), extras), - (type, meta) -> new CraftMetaItem(meta)); - - private static final ItemMetaData SIGNED_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, -- item -> new CraftMetaBookSigned(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBookSigned(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaBookSigned signed ? signed : new CraftMetaBookSigned(meta)); - - private static final ItemMetaData WRITABLE_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, -- item -> new CraftMetaBook(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBook(item.getComponentsPatch(), extras), - (type, meta) -> meta != null && meta.getClass().equals(CraftMetaBook.class) ? (BookMeta) meta : new CraftMetaBook(meta)); - - private static final ItemMetaData SKULL_META_DATA = new ItemMetaData<>(SkullMeta.class, -- item -> new CraftMetaSkull(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaSkull(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaSkull skull ? skull : new CraftMetaSkull(meta)); - - private static final ItemMetaData ARMOR_META_DATA = new ItemMetaData<>(ArmorMeta.class, -- item -> new CraftMetaArmor(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaArmor(item.getComponentsPatch(), extras), - (type, meta) -> meta != null && meta.getClass().equals(CraftMetaArmor.class) ? (ArmorMeta) meta : new CraftMetaArmor(meta)); - - private static final ItemMetaData COLORABLE_ARMOR_META_DATA = new ItemMetaData<>(ColorableArmorMeta.class, -- item -> new CraftMetaColorableArmor(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaColorableArmor(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof ColorableArmorMeta colorable ? colorable : new CraftMetaColorableArmor(meta)); - - private static final ItemMetaData LEATHER_ARMOR_META_DATA = new ItemMetaData<>(LeatherArmorMeta.class, -- item -> new CraftMetaLeatherArmor(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaLeatherArmor(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaLeatherArmor leather ? leather : new CraftMetaLeatherArmor(meta)); - - private static final ItemMetaData POTION_META_DATA = new ItemMetaData<>(PotionMeta.class, -- item -> new CraftMetaPotion(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaPotion(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaPotion potion ? potion : new CraftMetaPotion(meta)); - - private static final ItemMetaData MAP_META_DATA = new ItemMetaData<>(MapMeta.class, -- item -> new CraftMetaMap(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaMap(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaMap map ? map : new CraftMetaMap(meta)); - - private static final ItemMetaData FIREWORK_META_DATA = new ItemMetaData<>(FireworkMeta.class, -- item -> new CraftMetaFirework(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaFirework(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaFirework firework ? firework : new CraftMetaFirework(meta)); - - private static final ItemMetaData CHARGE_META_DATA = new ItemMetaData<>(FireworkEffectMeta.class, -- item -> new CraftMetaCharge(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaCharge(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaCharge charge ? charge : new CraftMetaCharge(meta)); - - private static final ItemMetaData ENCHANTED_BOOK_META_DATA = new ItemMetaData<>(EnchantmentStorageMeta.class, -- item -> new CraftMetaEnchantedBook(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaEnchantedBook(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaEnchantedBook enchantedBook ? enchantedBook : new CraftMetaEnchantedBook(meta)); - - private static final ItemMetaData BANNER_META_DATA = new ItemMetaData<>(BannerMeta.class, -- item -> new CraftMetaBanner(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBanner(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaBanner banner ? banner : new CraftMetaBanner(meta)); - - private static final ItemMetaData SPAWN_EGG_META_DATA = new ItemMetaData<>(SpawnEggMeta.class, -- item -> new CraftMetaSpawnEgg(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaSpawnEgg(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaSpawnEgg spawnEgg ? spawnEgg : new CraftMetaSpawnEgg(meta)); - - private static final ItemMetaData ARMOR_STAND_META_DATA = new ItemMetaData<>(ArmorStandMeta.class, // paper -- item -> new CraftMetaArmorStand(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaArmorStand(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaArmorStand armorStand ? armorStand : new CraftMetaArmorStand(meta)); - - private static final ItemMetaData KNOWLEDGE_BOOK_META_DATA = new ItemMetaData<>(KnowledgeBookMeta.class, -- item -> new CraftMetaKnowledgeBook(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaKnowledgeBook(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaKnowledgeBook knowledgeBook ? knowledgeBook : new CraftMetaKnowledgeBook(meta)); - - private static final ItemMetaData BLOCK_STATE_META_DATA = new ItemMetaData<>(BlockStateMeta.class, -- item -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem())), -+ (item, extras) -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem()), extras), - (type, meta) -> new CraftMetaBlockState(meta, type.asMaterial())); - - private static final ItemMetaData SHIELD_META_DATA = new ItemMetaData<>(ShieldMeta.class, -- item -> new CraftMetaShield(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaShield(item.getComponentsPatch(), extras), - (type, meta) -> new CraftMetaShield(meta)); - - private static final ItemMetaData TROPICAL_FISH_BUCKET_META_DATA = new ItemMetaData<>(TropicalFishBucketMeta.class, -- item -> new CraftMetaTropicalFishBucket(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaTropicalFishBucket(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaTropicalFishBucket tropicalFishBucket ? tropicalFishBucket : new CraftMetaTropicalFishBucket(meta)); - - private static final ItemMetaData AXOLOTL_BUCKET_META_DATA = new ItemMetaData<>(AxolotlBucketMeta.class, -- item -> new CraftMetaAxolotlBucket(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaAxolotlBucket(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaAxolotlBucket axolotlBucket ? axolotlBucket : new CraftMetaAxolotlBucket(meta)); - - private static final ItemMetaData CROSSBOW_META_DATA = new ItemMetaData<>(CrossbowMeta.class, -- item -> new CraftMetaCrossbow(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaCrossbow(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaCrossbow crossbow ? crossbow : new CraftMetaCrossbow(meta)); - - private static final ItemMetaData SUSPICIOUS_STEW_META_DATA = new ItemMetaData<>(SuspiciousStewMeta.class, -- item -> new CraftMetaSuspiciousStew(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaSuspiciousStew(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaSuspiciousStew suspiciousStew ? suspiciousStew : new CraftMetaSuspiciousStew(meta)); - - private static final ItemMetaData ENTITY_TAG_META_DATA = new ItemMetaData<>(ItemMeta.class, -- item -> new CraftMetaEntityTag(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaEntityTag(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaEntityTag entityTag ? entityTag : new CraftMetaEntityTag(meta)); - - private static final ItemMetaData COMPASS_META_DATA = new ItemMetaData<>(CompassMeta.class, -- item -> new CraftMetaCompass(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaCompass(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaCompass compass ? compass : new CraftMetaCompass(meta)); - - private static final ItemMetaData BUNDLE_META_DATA = new ItemMetaData<>(BundleMeta.class, -- item -> new CraftMetaBundle(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBundle(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaBundle bundle ? bundle : new CraftMetaBundle(meta)); - - private static final ItemMetaData MUSIC_INSTRUMENT_META_DATA = new ItemMetaData<>(MusicInstrumentMeta.class, -- item -> new CraftMetaMusicInstrument(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaMusicInstrument(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaMusicInstrument musicInstrument ? musicInstrument : new CraftMetaMusicInstrument(meta)); - - private static final ItemMetaData OMINOUS_BOTTLE_META_DATA = new ItemMetaData<>(OminousBottleMeta.class, -- item -> new CraftMetaOminousBottle(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaOminousBottle(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaOminousBottle musicInstrument ? musicInstrument : new CraftMetaOminousBottle(meta)); - - // We use if instead of a set, since the result gets cached in CraftItemType, -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 7228d43d331de16cbaa0e97c7e3fa45c0bc89558..dfdabf86433d323966a748baef769cf0462d3f38 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -173,10 +173,11 @@ public final class CraftItemStack extends ItemStack { - } else if (this.handle == null) { - this.handle = new net.minecraft.world.item.ItemStack(CraftItemType.bukkitToMinecraft(type), 1); - } else { -+ final Material oldType = CraftMagicNumbers.getMaterial(this.handle.getItem()); // Paper - this.handle.setItem(CraftItemType.bukkitToMinecraft(type)); - if (this.hasItemMeta()) { - // This will create the appropriate item meta, which will contain all the data we intend to keep -- CraftItemStack.setItemMeta(this.handle, CraftItemStack.getItemMeta(this.handle)); -+ this.adjustTagForItemMeta(oldType); // Paper - } - } - this.setData(null); -@@ -337,6 +338,19 @@ public final class CraftItemStack extends ItemStack { - public ItemMeta getItemMeta() { - return CraftItemStack.getItemMeta(this.handle); - } -+ // Paper start - improve handled tags on type change -+ public void adjustTagForItemMeta(final Material oldType) { -+ final CraftMetaItem oldMeta = (CraftMetaItem) CraftItemFactory.instance().getItemMeta(oldType); -+ final ItemMeta newMeta; -+ if (oldMeta == null) { -+ newMeta = getItemMeta(this.handle); -+ } else { -+ final java.util.Set> extraHandledDcts = new java.util.HashSet<>(CraftMetaItem.getTopLevelHandledDcts(oldMeta.getClass())); -+ newMeta = getItemMeta(this.handle, CraftItemType.minecraftToBukkitNew(this.handle.getItem()), extraHandledDcts); -+ } -+ this.setItemMeta(newMeta); -+ } -+ // Paper end - improve handled tags on type change - // Paper start - public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { - final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); -@@ -349,12 +363,17 @@ public final class CraftItemStack extends ItemStack { - } - public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType) { - // Paper end -+ // Paper start - handled tags on type change -+ return getItemMeta(item, metaForType, null); -+ } -+ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType, final java.util.Set> extraHandledDcts) { -+ // Paper end - handled tags on type change - if (!CraftItemStack.hasItemMeta(item)) { - return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item)); - } - -- if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item); } // Paper -- return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item); -+ if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item, extraHandledDcts); } // Paper -+ return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item, extraHandledDcts); // Paper - } - - static Material getType(net.minecraft.world.item.ItemStack item) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -index 6d76cc1db3ac3f1ae74c13511937fb86082a0b3d..f4a6ee6dfcb2d516a9a1a9c81494b50a629110e4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -@@ -114,8 +114,8 @@ public class CraftItemType implements ItemType.Typed, Han - return this.item; - } - -- public M getItemMeta(net.minecraft.world.item.ItemStack itemStack) { -- return this.itemMetaData.get().fromItemStack().apply(itemStack); -+ public M getItemMeta(net.minecraft.world.item.ItemStack itemStack, final java.util.Set> extraHandledDcts) { -+ return this.itemMetaData.get().fromItemStack().apply(itemStack, extraHandledDcts); - } - - public M getItemMeta(ItemMeta itemMeta) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -index 0d3b1692af010bfd7ea83e22e9571dc954906f71..e83a662f82b144b11a003a682633cd0ee797fd19 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -@@ -34,8 +34,8 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { - } - } - -- CraftMetaArmor(DataComponentPatch tag) { -- super(tag); -+ CraftMetaArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaArmor.TRIM).ifPresent((trimCompound) -> { - TrimMaterial trimMaterial = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL, trimCompound.material()).orElse(null); // Paper - fix upstream not being correct -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java -index ecce5d0da946ca279c5608068442cc53437dd2a5..00b5c4ab6111f980db1b9e99f901667741266440 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java -@@ -35,8 +35,8 @@ public class CraftMetaArmorStand extends CraftMetaItem implements com.destroysto - this.entityTag = armorStand.entityTag; - } - -- CraftMetaArmorStand(DataComponentPatch tag) { -- super(tag); -+ CraftMetaArmorStand(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaArmorStand.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -index c4beb94d8e5448e69f31f30299448f344b5d8f59..169fefb64e1af444f7c2efb1234cb6e7779fb717 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -@@ -36,8 +36,8 @@ public class CraftMetaAxolotlBucket extends CraftMetaItem implements AxolotlBuck - this.bucketEntityTag = bucket.bucketEntityTag; - } - -- CraftMetaAxolotlBucket(DataComponentPatch tag) { -- super(tag); -+ CraftMetaAxolotlBucket(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaAxolotlBucket.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -index eb44c19f6af624df458981e46c73a64358d6e1ce..d0a8cd89da3b8d87248494056470c306f8fb5ae8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -@@ -34,8 +34,8 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { - this.patterns = new ArrayList(banner.patterns); - } - -- CraftMetaBanner(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBanner(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBanner.PATTERNS).ifPresent((entityTag) -> { - List patterns = entityTag.layers(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -index 3985e5b4e2d65faa8eaea1d4a2acc6fb1e64f959..413e41f113226b8a2e9b30bb519076d78e451fa0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -@@ -73,8 +73,8 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - this.position = te.position; - } - -- CraftMetaBlockState(DataComponentPatch tag, Material material) { -- super(tag); -+ CraftMetaBlockState(DataComponentPatch tag, Material material, final Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - this.material = material; - - getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((blockTag) -> { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -index 32e5188442551b3e72e1d4826d836d622d0e438a..257c835bc280eee9ee73ae75b5249bb568a687d0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -@@ -64,8 +64,8 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta, WritableBo - } - } - -- CraftMetaBook(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBook.BOOK_CONTENT).ifPresent((writable) -> { - List> pages = writable.pages(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -index fd3b12477c30d1eabdbe57ea779027931e9dd957..cbb3d80cc7cd81b2505dff999a0baede737165f7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -@@ -78,8 +78,8 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta { - } - } - -- CraftMetaBookSigned(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBookSigned(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBookSigned.BOOK_CONTENT).ifPresent((written) -> { - this.title = written.title().raw(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -index 30533ce683e0471742b27d1d31df20def8ea169c..2736a87a6c481da0575e6e29ea08faa539c24378 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -@@ -34,8 +34,8 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { - } - } - -- CraftMetaBundle(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBundle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBundle.ITEMS).ifPresent((bundle) -> { - bundle.items().forEach((item) -> { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java -index 72340e7269a5464d72abe8370c8113f3de9573d2..56c6784e29cecf8655282235959de536d07c1e08 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java -@@ -29,8 +29,8 @@ class CraftMetaCharge extends CraftMetaItem implements FireworkEffectMeta { - this.setEffect(SerializableMeta.getObject(FireworkEffect.class, map, CraftMetaCharge.EXPLOSION.BUKKIT, true)); - } - -- CraftMetaCharge(DataComponentPatch tag) { -- super(tag); -+ CraftMetaCharge(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaCharge.EXPLOSION).ifPresent((f) -> { - try { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -index 366fec1aee66de4031727a1383acebd319eeef88..6517ec4933b0eae761fceb117ea1db175755d0b1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -@@ -18,8 +18,8 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable - CraftMetaLeatherArmor.readColor(this, meta); - } - -- CraftMetaColorableArmor(DataComponentPatch tag) { -- super(tag); -+ CraftMetaColorableArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - CraftMetaLeatherArmor.readColor(this, tag); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -index 607e23040383576b2805c25947a69f6efe6d2c88..69a112b3a9726966aecbe687d905fd1a11cfa1e3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -@@ -50,8 +50,8 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - this.tracked = compassMeta.tracked; - } - -- CraftMetaCompass(DataComponentPatch tag) { -- super(tag); -+ CraftMetaCompass(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaCompass.LODESTONE_TARGET).ifPresent((lodestoneTarget) -> { - lodestoneTarget.target().ifPresent((target) -> { - this.lodestoneWorld = target.dimension(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -index c278af519308c84ad76fc2312046980c01c528ba..0807c2172c5a4bee675cef265a45a9350e98b880 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -@@ -36,8 +36,8 @@ public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta { - } - } - -- CraftMetaCrossbow(DataComponentPatch tag) { -- super(tag); -+ CraftMetaCrossbow(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaCrossbow.CHARGED_PROJECTILES).ifPresent((p) -> { - List list = p.getItems(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -index 19af55ec2bf62b70bd3be44f499b32f5efe71ab1..c93f769ee6c55022653696da45de568fcf7589fe 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -@@ -32,8 +32,8 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage - } - } - -- CraftMetaEnchantedBook(DataComponentPatch tag) { -- super(tag); -+ CraftMetaEnchantedBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { - this.enchantments = buildEnchantments(itemEnchantments); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -index 3ff0340c40e9dc9a6e690de15ccade7a0c4e8f02..3f6c5cbbf63631e4b72dc43558651ea94f31ca78 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -@@ -39,8 +39,8 @@ public class CraftMetaEntityTag extends CraftMetaItem { - this.entityTag = entity.entityTag; - } - -- CraftMetaEntityTag(DataComponentPatch tag) { -- super(tag); -+ CraftMetaEntityTag(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaEntityTag.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -index 4941e0afff8df5f10f06c715b54bf58eb86051c5..566d893a413fd04b99e83dc2da8fe958a48492a8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -@@ -60,8 +60,8 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - } - } - -- CraftMetaFirework(DataComponentPatch tag) { -- super(tag); -+ CraftMetaFirework(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaFirework.FIREWORKS).ifPresent((fireworks) -> { - this.power = fireworks.flightDuration(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 6b3eed94c26bc16177f9b9fadd140f9a89163af2..13b19adc21ece31476b2980c5bc01a50f15df634 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -389,7 +389,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - // Paper end - } - -- CraftMetaItem(DataComponentPatch tag) { -+ CraftMetaItem(DataComponentPatch tag, Set> extraHandledTags) { // Paper - improve handled tags on type changes - CraftMetaItem.getOrEmpty(tag, CraftMetaItem.NAME).ifPresent((component) -> { - this.displayName = component; - }); -@@ -521,9 +521,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - }); - // Paper end - fix ItemFlags - -+ // Paper start - improve checking handled data component types -+ Set> handledTags = getTopLevelHandledDcts(this.getClass()); -+ if (extraHandledTags != null) { -+ extraHandledTags.addAll(handledTags); -+ handledTags = extraHandledTags; -+ } -+ // Paper end - improve checking handled data component types - Set, Optional>> keys = tag.entrySet(); - for (Map.Entry, Optional> key : keys) { -- if (!CraftMetaItem.getHandledTags().contains(key.getKey())) { -+ if (!handledTags.contains(key.getKey())) { // Paper - improve checking handled data component types - key.getValue().ifPresent((value) -> { - this.unhandledTags.set((DataComponentType) key.getKey(), value); - }); -@@ -2351,75 +2358,83 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.version = version; - } - -- public static Set getHandledTags() { -- synchronized (CraftMetaItem.HANDLED_TAGS) { -- if (CraftMetaItem.HANDLED_TAGS.isEmpty()) { -- CraftMetaItem.HANDLED_TAGS.addAll(Arrays.asList( -- CraftMetaItem.NAME.TYPE, -- CraftMetaItem.ITEM_NAME.TYPE, -- CraftMetaItem.LORE.TYPE, -- CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, -- CraftMetaItem.ENCHANTABLE.TYPE, -- CraftMetaItem.BLOCK_DATA.TYPE, -- CraftMetaItem.REPAIR.TYPE, -- CraftMetaItem.ENCHANTMENTS.TYPE, -- CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, -- CraftMetaItem.HIDE_TOOLTIP.TYPE, -- CraftMetaItem.TOOLTIP_STYLE.TYPE, -- CraftMetaItem.ITEM_MODEL.TYPE, -- CraftMetaItem.UNBREAKABLE.TYPE, -- CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, -- CraftMetaItem.GLIDER.TYPE, -- CraftMetaItem.DAMAGE_RESISTANT.TYPE, -- CraftMetaItem.MAX_STACK_SIZE.TYPE, -- CraftMetaItem.RARITY.TYPE, -- CraftMetaItem.USE_REMAINDER.TYPE, -- CraftMetaItem.USE_COOLDOWN.TYPE, -- CraftMetaItem.FOOD.TYPE, -- CraftMetaItem.TOOL.TYPE, -- CraftMetaItem.EQUIPPABLE.TYPE, -- CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, -- CraftMetaItem.DAMAGE.TYPE, -- CraftMetaItem.MAX_DAMAGE.TYPE, -- CraftMetaItem.CUSTOM_DATA.TYPE, -- CraftMetaItem.ATTRIBUTES.TYPE, -- CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper -- CraftMetaItem.CAN_BREAK.TYPE, // Paper -- CraftMetaArmor.TRIM.TYPE, -- CraftMetaArmorStand.ENTITY_TAG.TYPE, -- CraftMetaBanner.PATTERNS.TYPE, -- CraftMetaEntityTag.ENTITY_TAG.TYPE, -- CraftMetaLeatherArmor.COLOR.TYPE, -- CraftMetaMap.MAP_POST_PROCESSING.TYPE, -- CraftMetaMap.MAP_COLOR.TYPE, -- CraftMetaMap.MAP_ID.TYPE, -- CraftMetaPotion.POTION_CONTENTS.TYPE, -- CraftMetaShield.BASE_COLOR.TYPE, -- CraftMetaSkull.SKULL_PROFILE.TYPE, -- CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE, -- CraftMetaSpawnEgg.ENTITY_TAG.TYPE, -- CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE, -- CraftMetaBook.BOOK_CONTENT.TYPE, -- CraftMetaBookSigned.BOOK_CONTENT.TYPE, -- CraftMetaFirework.FIREWORKS.TYPE, -- CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE, -- CraftMetaCharge.EXPLOSION.TYPE, -- CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE, -- CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, -- CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE, -- CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, -- CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE, -- CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE, -- CraftMetaSuspiciousStew.EFFECTS.TYPE, -- CraftMetaCompass.LODESTONE_TARGET.TYPE, -- CraftMetaBundle.ITEMS.TYPE, -- CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE, -- CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE -- )); -- } -- return CraftMetaItem.HANDLED_TAGS; -+ // Paper start - improve checking handled tags -+ @org.jetbrains.annotations.VisibleForTesting -+ public static final Map, Set>> HANDLED_DCTS_PER_TYPE = new HashMap<>(); -+ private static final Set> DEFAULT_HANDLED_DCTS = Set.of( -+ CraftMetaItem.NAME.TYPE, -+ CraftMetaItem.ITEM_NAME.TYPE, -+ CraftMetaItem.LORE.TYPE, -+ CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, -+ CraftMetaItem.ENCHANTABLE.TYPE, -+ CraftMetaItem.BLOCK_DATA.TYPE, -+ CraftMetaItem.REPAIR.TYPE, -+ CraftMetaItem.ENCHANTMENTS.TYPE, -+ CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, -+ CraftMetaItem.HIDE_TOOLTIP.TYPE, -+ CraftMetaItem.TOOLTIP_STYLE.TYPE, -+ CraftMetaItem.ITEM_MODEL.TYPE, -+ CraftMetaItem.UNBREAKABLE.TYPE, -+ CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, -+ CraftMetaItem.GLIDER.TYPE, -+ CraftMetaItem.DAMAGE_RESISTANT.TYPE, -+ CraftMetaItem.MAX_STACK_SIZE.TYPE, -+ CraftMetaItem.RARITY.TYPE, -+ CraftMetaItem.USE_REMAINDER.TYPE, -+ CraftMetaItem.USE_COOLDOWN.TYPE, -+ CraftMetaItem.FOOD.TYPE, -+ CraftMetaItem.TOOL.TYPE, -+ CraftMetaItem.EQUIPPABLE.TYPE, -+ CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, -+ CraftMetaItem.DAMAGE.TYPE, -+ CraftMetaItem.MAX_DAMAGE.TYPE, -+ CraftMetaItem.CUSTOM_DATA.TYPE, -+ CraftMetaItem.ATTRIBUTES.TYPE, -+ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper -+ CraftMetaItem.CAN_BREAK.TYPE // Paper -+ ); -+ public static Set> getTopLevelHandledDcts(final Class clazz) { -+ synchronized (HANDLED_DCTS_PER_TYPE) { -+ if (HANDLED_DCTS_PER_TYPE.isEmpty()) { -+ final Map, Set>> map = new HashMap<>(); -+ map.put(CraftMetaArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE)); -+ map.put(CraftMetaArmorStand.class, Set.of(CraftMetaArmorStand.ENTITY_TAG.TYPE)); -+ map.put(CraftMetaAxolotlBucket.class, Set.of(CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE)); -+ map.put(CraftMetaBanner.class, Set.of(CraftMetaBanner.PATTERNS.TYPE)); // banner uses same tag as block state -+ map.put(CraftMetaShield.class, Set.of(CraftMetaShield.BASE_COLOR.TYPE, CraftMetaBanner.PATTERNS.TYPE)); -+ map.put(CraftMetaBlockState.class, Set.of(CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE)); -+ map.put(CraftMetaBook.class, Set.of(CraftMetaBook.BOOK_CONTENT.TYPE)); -+ map.put(CraftMetaBookSigned.class, Set.of(CraftMetaBookSigned.BOOK_CONTENT.TYPE)); -+ map.put(CraftMetaBundle.class, Set.of(CraftMetaBundle.ITEMS.TYPE)); -+ map.put(CraftMetaCharge.class, Set.of(CraftMetaCharge.EXPLOSION.TYPE)); -+ map.put(CraftMetaColorableArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE, CraftMetaLeatherArmor.COLOR.TYPE)); -+ map.put(CraftMetaCompass.class, Set.of(CraftMetaCompass.LODESTONE_TARGET.TYPE)); -+ map.put(CraftMetaCrossbow.class, Set.of(CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE)); -+ map.put(CraftMetaEnchantedBook.class, Set.of(CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE)); -+ map.put(CraftMetaEntityTag.class, Set.of(CraftMetaEntityTag.ENTITY_TAG.TYPE)); -+ map.put(CraftMetaFirework.class, Set.of(CraftMetaFirework.FIREWORKS.TYPE)); -+ map.put(CraftMetaKnowledgeBook.class, Set.of(CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE)); -+ map.put(CraftMetaLeatherArmor.class, Set.of(CraftMetaLeatherArmor.COLOR.TYPE)); -+ map.put(CraftMetaMap.class, Set.of(CraftMetaMap.MAP_COLOR.TYPE, CraftMetaMap.MAP_POST_PROCESSING.TYPE, CraftMetaMap.MAP_ID.TYPE)); -+ map.put(CraftMetaMusicInstrument.class, Set.of(CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE)); -+ map.put(CraftMetaOminousBottle.class, Set.of(CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE)); -+ map.put(CraftMetaPotion.class, Set.of(CraftMetaPotion.POTION_CONTENTS.TYPE)); -+ map.put(CraftMetaSkull.class, Set.of(CraftMetaSkull.SKULL_PROFILE.TYPE, CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE)); -+ map.put(CraftMetaSpawnEgg.class, Set.of(CraftMetaSpawnEgg.ENTITY_TAG.TYPE)); -+ map.put(CraftMetaSuspiciousStew.class, Set.of(CraftMetaSuspiciousStew.EFFECTS.TYPE)); -+ map.put(CraftMetaTropicalFishBucket.class, Set.of(CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE)); -+ -+ for (final Map.Entry, Set>> entry : map.entrySet()) { -+ final ArrayList> topLevelTags = new ArrayList<>(entry.getValue()); -+ // add tags common to CraftMetaItem to all -+ topLevelTags.addAll(DEFAULT_HANDLED_DCTS); -+ HANDLED_DCTS_PER_TYPE.put(entry.getKey(), Set.copyOf(topLevelTags)); -+ } -+ } -+ return HANDLED_DCTS_PER_TYPE.getOrDefault(clazz, DEFAULT_HANDLED_DCTS); - } - } -+ // Paper end - improve checking handled data component types - - protected static Optional getOrEmpty(DataComponentPatch tag, ItemMetaKeyType type) { - Optional result = tag.get(type.TYPE); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java -index 68c0a6d5e06a44ddddddb9cbe093ed6814380444..4dc7adb626ccb74b7e3a60c5a7250d0dc9703997 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java -@@ -32,8 +32,8 @@ public class CraftMetaKnowledgeBook extends CraftMetaItem implements KnowledgeBo - } - } - -- CraftMetaKnowledgeBook(DataComponentPatch tag) { -- super(tag); -+ CraftMetaKnowledgeBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaKnowledgeBook.BOOK_RECIPES).ifPresent((pages) -> { - for (int i = 0; i < pages.size(); i++) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -index 75a8ad69902103a2e33a457c3225a33860d075ed..e8c950aa74d31bf7a9128f4acc4bccee26bbcd7f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -@@ -25,8 +25,8 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - CraftMetaLeatherArmor.readColor(this, meta); - } - -- CraftMetaLeatherArmor(DataComponentPatch tag) { -- super(tag); -+ CraftMetaLeatherArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - CraftMetaLeatherArmor.readColor(this, tag); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -index 08e18dcabbf52aae5c3843d49a72d1d52baa729b..149356981e586e4f67d4543d3df94a2ea99333fc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -@@ -44,8 +44,8 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { - this.color = map.color; - } - -- CraftMetaMap(DataComponentPatch tag) { -- super(tag); -+ CraftMetaMap(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaMap.MAP_ID).ifPresent((mapId) -> { - this.mapId = mapId.id(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -index 76a3e4893cbdba903a712d6db1d30b9c644795be..a80b9b142ca99c7c0257b1bdeb059dce5f92ae93 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -@@ -26,8 +26,8 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst - } - } - -- CraftMetaMusicInstrument(DataComponentPatch tag) { -- super(tag); -+ CraftMetaMusicInstrument(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT).ifPresent((instrument) -> { - this.instrument = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.INSTRUMENT, instrument).orElse(null); // Paper - fix upstream not handling inlined instrument -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -index ed272c7eb435677de5f6b106a6012c472decbb62..b118d8ecb505d187c02bb158f14df333f487a87f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -@@ -24,8 +24,8 @@ public class CraftMetaOminousBottle extends CraftMetaItem implements OminousBott - this.ominousBottleAmplifier = bottleMeta.ominousBottleAmplifier; - } - -- CraftMetaOminousBottle(DataComponentPatch tag) { -- super(tag); -+ CraftMetaOminousBottle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER).ifPresent((amplifier) -> { - this.ominousBottleAmplifier = amplifier.value(); - }); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -index 533c600d632eb733c121f5d8189142726b091713..6f0eebcaffa20337cf5a7f8485f891c690d948ae 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -@@ -54,8 +54,8 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - } - } - -- CraftMetaPotion(DataComponentPatch tag) { -- super(tag); -+ CraftMetaPotion(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaPotion.POTION_CONTENTS).ifPresent((potionContents) -> { - potionContents.potion().ifPresent((potion) -> { - this.type = CraftPotionType.minecraftHolderToBukkit(potion); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -index bcd6cc29e4e621805cbd923d747f652ced240c6d..967d8940aec0065bce496d5d7a8c73de5733bd2c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -@@ -42,8 +42,8 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - } - } - -- CraftMetaShield(DataComponentPatch tag) { -- super(tag); -+ CraftMetaShield(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper - improve checking handled tags in item meta -+ super(tag, extraHandledDcts); // Paper - improve checking handled tags in item meta - - getOrEmpty(tag, CraftMetaShield.BASE_COLOR).ifPresent((color) -> { - this.banner = CraftMetaShield.getBlockState(DyeColor.getByWoolData((byte) color.getId())); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -index ca714e165e453d1072d083441d8b985290ada75a..302906467b12189e21633369c005736863f46dd5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -@@ -48,8 +48,8 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { - this.noteBlockSound = skullMeta.noteBlockSound; - } - -- CraftMetaSkull(DataComponentPatch tag) { -- super(tag); -+ CraftMetaSkull(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaSkull.SKULL_PROFILE).ifPresent(this::setProfile); - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -index 6c2c3b514be0dab47f3e44f65bdc6a3574e59b7c..8ddf091b3ff1262b6c97e8fe72e0a80db5e1037d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -@@ -33,8 +33,8 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { - this.entityTag = egg.entityTag; - } - -- CraftMetaSpawnEgg(DataComponentPatch tag) { -- super(tag); -+ CraftMetaSpawnEgg(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaSpawnEgg.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java -index 248efddbad2bfee4f9aa33ec738b5353054eda61..7a43e326e51300306b9c5c23a16ffae92030bd2b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java -@@ -33,8 +33,8 @@ public class CraftMetaSuspiciousStew extends CraftMetaItem implements Suspicious - } - } - -- CraftMetaSuspiciousStew(DataComponentPatch tag) { -- super(tag); -+ CraftMetaSuspiciousStew(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaSuspiciousStew.EFFECTS).ifPresent((suspiciousStewEffects) -> { - List list = suspiciousStewEffects.effects(); - int length = list.size(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -index a514fe98d3d2b65d2cfd029079c69189bcb99c01..17705059b81942e4df43a4a5180092e09c985ade 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -@@ -38,8 +38,8 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB - this.bucketEntityTag = bucket.bucketEntityTag; - } - -- CraftMetaTropicalFishBucket(DataComponentPatch tag) { -- super(tag); -+ CraftMetaTropicalFishBucket(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaTropicalFishBucket.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -index 91cfa32272770cdfe56d97154ea9db4e2ed8a328..9cc1ef5c9221dd7d2069b280f0c91ce9439a995a 100644 ---- a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -@@ -97,7 +97,7 @@ public class DeprecatedItemMetaCustomValueTest { - CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); - itemMeta.applyToItem(compound); - -- assertEquals(itemMeta, new CraftMetaItem(compound.build())); -+ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper - } - - @Test -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..df20446af3d43c624278d1a25f31f702677c8d96 ---- /dev/null -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java -@@ -0,0 +1,33 @@ -+package org.bukkit.craftbukkit.inventory; -+ -+import io.github.classgraph.ClassGraph; -+import io.github.classgraph.ClassInfo; -+import io.github.classgraph.ClassInfoList; -+import io.github.classgraph.ScanResult; -+import org.bukkit.support.environment.AllFeatures; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertFalse; -+import static org.junit.jupiter.api.Assertions.assertTrue; -+ -+// in cb package because of package-private stuff -+@AllFeatures -+class MetaHandledTagsTest { -+ -+ @Test -+ public void checkAllMetasHaveHandledTags() { -+ try (final ScanResult result = new ClassGraph() -+ .whitelistPackages("org.bukkit.craftbukkit.inventory") -+ .enableClassInfo().scan()) { -+ final ClassInfoList subclasses = result.getSubclasses(CraftMetaItem.class.getName()); -+ assertFalse(subclasses.isEmpty(), "found 0 sub types"); -+ for (final ClassInfo subclass : subclasses) { -+ final Class clazz = subclass.loadClass(CraftMetaItem.class); -+ CraftMetaItem.getTopLevelHandledDcts(clazz); // load into map -+ assertTrue(CraftMetaItem.HANDLED_DCTS_PER_TYPE.containsKey(clazz), subclass.getName() + " not found in handled tags map"); -+ } -+ } catch (Exception e) { -+ throw new RuntimeException(e); -+ } -+ } -+} -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -index 5b16e6f5e5517eed218e4b60ecd75f8b80712e89..130c4500a5e854480962c8f720b1df4c67d43c33 100644 ---- a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -@@ -131,7 +131,7 @@ public class PersistentDataContainerTest { - CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); - itemMeta.applyToItem(compound); - -- assertEquals(itemMeta, new CraftMetaItem(compound.build())); -+ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper - } - - @Test -@@ -464,7 +464,7 @@ public class PersistentDataContainerTest { - - @Test - public void testEmptyListApplicationToAnyType() throws IOException { -- final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY); -+ final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY, null); // Paper - final PersistentDataContainer container = craftItem.getPersistentDataContainer(); - - container.set(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings(), List.of()); -@@ -477,7 +477,7 @@ public class PersistentDataContainerTest { - final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator(); - craftItem.applyToItem(storage); - -- final CraftMetaItem readItem = new CraftMetaItem(storage.build()); -+ final CraftMetaItem readItem = new CraftMetaItem(storage.build(), null); // Paper - final PersistentDataContainer readContainer = readItem.getPersistentDataContainer(); - - assertTrue(readContainer.has(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings())); diff --git a/patches/server/0952-Added-API-to-get-player-ha-proxy-address.patch b/patches/server/0952-Added-API-to-get-player-ha-proxy-address.patch new file mode 100644 index 0000000000..1871d14810 --- /dev/null +++ b/patches/server/0952-Added-API-to-get-player-ha-proxy-address.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nostalfinals +Date: Mon, 8 Apr 2024 23:24:38 +0800 +Subject: [PATCH] Added API to get player ha proxy address + + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index ea16dfa718b526d6520d7fcfc21d28f972f1f2bf..4b9da6e2140b14f1e56056f5e9e94b2169d85501 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -153,6 +153,7 @@ public class Connection extends SimpleChannelInboundHandler> { + this.stopReadingPackets = true; + } + // Paper end - packet limiter ++ @Nullable public SocketAddress haProxyAddress; // Paper - Add API to get player's proxy address + + public Connection(PacketFlow side) { + this.receiving = side; +diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +index c62df32af11636ad408b584fcc590590ce4fb0d0..baed0bb80d44973f9323bbe536551182979caff2 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java ++++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +@@ -144,6 +144,13 @@ public class ServerConnectionListener { + + Connection connection = (Connection) channel.pipeline().get("packet_handler"); + connection.address = socketaddr; ++ ++ // Paper start - Add API to get player's proxy address ++ final String proxyAddress = message.destinationAddress(); ++ final int proxyPort = message.destinationPort(); ++ ++ connection.haProxyAddress = new java.net.InetSocketAddress(proxyAddress, proxyPort); ++ // Paper end - Add API to get player's proxy address + } + } else { + super.channelRead(ctx, msg); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 0a3d44ac5bfe252854377011ac363d52991c15ed..72b9bffb12ef94d029c9502be90fb8c1bd37a4d1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -270,7 +270,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public InetSocketAddress getAddress() { +- if (this.getHandle().connection.protocol() == null) return null; ++ if (this.getHandle().connection == null) return null; + + SocketAddress addr = this.getHandle().connection.getRemoteAddress(); + if (addr instanceof InetSocketAddress) { +@@ -280,6 +280,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + } + ++ // Paper start - Add API to get player's proxy address ++ @Override ++ public @Nullable InetSocketAddress getHAProxyAddress() { ++ if (this.getHandle().connection == null) return null; ++ ++ return this.getHandle().connection.connection.haProxyAddress instanceof final InetSocketAddress inetSocketAddress ? inetSocketAddress : null; ++ } ++ // Paper end - Add API to get player's proxy address ++ + public interface TransferCookieConnection { + + boolean isTransferred(); diff --git a/patches/server/0952-Expose-hasColor-to-leather-armor.patch b/patches/server/0952-Expose-hasColor-to-leather-armor.patch deleted file mode 100644 index 9166ad6261..0000000000 --- a/patches/server/0952-Expose-hasColor-to-leather-armor.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SoSeDiK -Date: Wed, 1 May 2024 10:58:50 +0300 -Subject: [PATCH] Expose #hasColor to leather armor - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -index 6517ec4933b0eae761fceb117ea1db175755d0b1..dc6398cfbd6e749733c3a681e1eb8ce15c3b2c5e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -@@ -100,4 +100,11 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable - } - return original != hash ? CraftMetaColorableArmor.class.hashCode() ^ hash : hash; - } -+ -+ // Paper start - Expose #hasColor to leather armor -+ @Override -+ public boolean isDyed() { -+ return hasColor(); -+ } -+ // Paper end - Expose #hasColor to leather armor - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -index e8c950aa74d31bf7a9128f4acc4bccee26bbcd7f..e76749bffaf5a0bbd3a8d35f882edcc3598351b9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -@@ -156,4 +156,11 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - builder.put(CraftMetaLeatherArmor.COLOR.BUKKIT, meta.getColor()); - } - } -+ -+ // Paper start - Expose #hasColor to leather armor -+ @Override -+ public boolean isDyed() { -+ return hasColor(); -+ } -+ // Paper end - Expose #hasColor to leather armor - } diff --git a/patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch b/patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch deleted file mode 100644 index 1871d14810..0000000000 --- a/patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nostalfinals -Date: Mon, 8 Apr 2024 23:24:38 +0800 -Subject: [PATCH] Added API to get player ha proxy address - - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index ea16dfa718b526d6520d7fcfc21d28f972f1f2bf..4b9da6e2140b14f1e56056f5e9e94b2169d85501 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -153,6 +153,7 @@ public class Connection extends SimpleChannelInboundHandler> { - this.stopReadingPackets = true; - } - // Paper end - packet limiter -+ @Nullable public SocketAddress haProxyAddress; // Paper - Add API to get player's proxy address - - public Connection(PacketFlow side) { - this.receiving = side; -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index c62df32af11636ad408b584fcc590590ce4fb0d0..baed0bb80d44973f9323bbe536551182979caff2 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -144,6 +144,13 @@ public class ServerConnectionListener { - - Connection connection = (Connection) channel.pipeline().get("packet_handler"); - connection.address = socketaddr; -+ -+ // Paper start - Add API to get player's proxy address -+ final String proxyAddress = message.destinationAddress(); -+ final int proxyPort = message.destinationPort(); -+ -+ connection.haProxyAddress = new java.net.InetSocketAddress(proxyAddress, proxyPort); -+ // Paper end - Add API to get player's proxy address - } - } else { - super.channelRead(ctx, msg); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 0a3d44ac5bfe252854377011ac363d52991c15ed..72b9bffb12ef94d029c9502be90fb8c1bd37a4d1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -270,7 +270,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public InetSocketAddress getAddress() { -- if (this.getHandle().connection.protocol() == null) return null; -+ if (this.getHandle().connection == null) return null; - - SocketAddress addr = this.getHandle().connection.getRemoteAddress(); - if (addr instanceof InetSocketAddress) { -@@ -280,6 +280,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - } - -+ // Paper start - Add API to get player's proxy address -+ @Override -+ public @Nullable InetSocketAddress getHAProxyAddress() { -+ if (this.getHandle().connection == null) return null; -+ -+ return this.getHandle().connection.connection.haProxyAddress instanceof final InetSocketAddress inetSocketAddress ? inetSocketAddress : null; -+ } -+ // Paper end - Add API to get player's proxy address -+ - public interface TransferCookieConnection { - - boolean isTransferred(); diff --git a/patches/server/0953-General-ItemMeta-fixes.patch b/patches/server/0953-General-ItemMeta-fixes.patch new file mode 100644 index 0000000000..9421f612dd --- /dev/null +++ b/patches/server/0953-General-ItemMeta-fixes.patch @@ -0,0 +1,2152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 27 Apr 2024 20:56:17 -0700 +Subject: [PATCH] General ItemMeta fixes + +== AT == +private-f net/minecraft/world/item/ItemStack components +public net/minecraft/world/food/FoodProperties DEFAULT_EAT_SECONDS +public org/bukkit/craftbukkit/block/CraftBlockStates getBlockState(Lorg/bukkit/World;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/entity/BlockEntity;)Lorg/bukkit/craftbukkit/block/CraftBlockState; +public net/minecraft/world/level/block/entity/BlockEntity saveId(Lnet/minecraft/nbt/CompoundTag;)V + +Co-authored-by: GhastCraftHD + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 98b5208baeaa12a5ff2788e457c542000d6ea48b..babd89f39c43b0c64709d99bf8aca6cdc6ca1b24 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -1361,6 +1361,11 @@ public final class ItemStack implements DataComponentHolder { + public void setItem(Item item) { + this.bukkitStack = null; // Paper + this.item = item; ++ // Paper start - change base component prototype ++ final DataComponentPatch patch = this.getComponentsPatch(); ++ this.components = new PatchedDataComponentMap(this.item.components()); ++ this.applyComponents(patch); ++ // Paper end - change base component prototype + } + // CraftBukkit end + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +index 645a7ec0709cbd3c0cfbf75f7b8622a67515f74c..39fc5aa6ac8c66d8dd7437262124b61c4c138689 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -147,6 +147,11 @@ public abstract class BlockEntity { + CompoundTag nbttagcompound = new CompoundTag(); + + this.saveAdditional(nbttagcompound, registries); ++ // Paper start - store PDC here as well ++ if (this.persistentDataContainer != null && !this.persistentDataContainer.isEmpty()) { ++ nbttagcompound.put("PublicBukkitValues", this.persistentDataContainer.toTagCompound()); ++ } ++ // Paper end + return nbttagcompound; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +index fe7e3e0628783d8d1be9635b689da8a9cb46c5d7..04ae258a2f8e98421340d29d5cceedec045171b7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +@@ -151,6 +151,19 @@ public abstract class CraftBlockEntityState extends Craft + return this.snapshot.getUpdateTag(this.getRegistryAccess()); + } + ++ // Paper start - properly save blockentity itemstacks ++ public CompoundTag getSnapshotCustomNbtOnly() { ++ this.applyTo(this.snapshot); ++ final CompoundTag nbt = this.snapshot.saveCustomOnly(this.getRegistryAccess()); ++ this.snapshot.removeComponentsFromTag(nbt); ++ if (!nbt.isEmpty()) { ++ // have to include the "id" if it's going to have block entity data ++ this.snapshot.saveId(nbt); ++ } ++ return nbt; ++ } ++ // Paper end ++ + // copies the data of the given tile entity to this block state + protected void load(T tileEntity) { + if (tileEntity != null && tileEntity != this.snapshot) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index dfdabf86433d323966a748baef769cf0462d3f38..bb2b4528692aed8e3341428697a60c0abee13779 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -291,7 +291,9 @@ public final class CraftItemStack extends ItemStack { + + @Override + public void removeEnchantments() { +- this.handle.remove(DataComponents.ENCHANTMENTS); ++ if (this.handle != null) { // Paper - fix NPE ++ this.handle.set(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); // Paper - set to default instead of removing the component ++ } // Paper + } + + @Override +@@ -353,7 +355,14 @@ public final class CraftItemStack extends ItemStack { + // Paper end - improve handled tags on type change + // Paper start + public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { +- final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); ++ // Paper start - support updating profile after resolving it ++ final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() { ++ @Override ++ void skullCallback(final net.minecraft.world.item.component.ResolvableProfile profile) { ++ itemStack.set(DataComponents.PROFILE, profile); ++ } ++ }; ++ // Paper end - support updating profile after resolving it + ((CraftMetaItem) itemMeta).applyToItem(tag); + itemStack.applyComponents(tag.build()); + } +@@ -401,15 +410,20 @@ public final class CraftItemStack extends ItemStack { + if (itemMeta == null) return true; + + if (!((CraftMetaItem) itemMeta).isEmpty()) { +- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); ++ // Paper start - support updating profile after resolving it ++ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() { ++ @Override ++ void skullCallback(final net.minecraft.world.item.component.ResolvableProfile resolvableProfile) { ++ item.set(DataComponents.PROFILE, resolvableProfile); ++ } ++ }; ++ // Paper end - support updating profile after resolving it + + ((CraftMetaItem) itemMeta).applyToItem(tag); +- item.restorePatch(tag.build()); +- } +- // SpigotCraft#463 this is required now by the Vanilla client, so mimic ItemStack constructor in ensuring it +- if (item.getItem() != null && item.getMaxDamage() > 0) { +- item.setDamageValue(item.getDamageValue()); ++ item.restorePatch(DataComponentPatch.EMPTY); // Paper - properly apply the new patch from itemmeta ++ item.applyComponents(tag.build()); // Paper - properly apply the new patch from itemmeta + } ++ // Paper - this is no longer needed + + return true; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java +index 169fefb64e1af444f7c2efb1234cb6e7779fb717..cb49ff5c94f33f00f626a31d958d2025819d1da8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java +@@ -118,14 +118,13 @@ public class CraftMetaAxolotlBucket extends CraftMetaItem implements AxolotlBuck + + @Override + public Axolotl.Variant getVariant() { ++ com.google.common.base.Preconditions.checkState(this.hasVariant(), "Variant is absent, check hasVariant first!"); // Paper - fix NPE + return Axolotl.Variant.values()[this.variant]; + } + + @Override + public void setVariant(Axolotl.Variant variant) { +- if (variant == null) { +- variant = Axolotl.Variant.LUCY; +- } ++ com.google.common.base.Preconditions.checkArgument(variant != null, "Variant cannot be null!"); // Paper + this.variant = variant.ordinal(); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +index d0a8cd89da3b8d87248494056470c306f8fb5ae8..fdc0c1d73bb523f003e4169589f1002375b9c88c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +@@ -69,6 +69,7 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { + void applyToItem(CraftMetaItem.Applicator tag) { + super.applyToItem(tag); + ++ if (this.patterns.isEmpty()) return; // Paper - don't write empty patterns + List newPatterns = new ArrayList<>(); + + for (Pattern p : this.patterns) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +index 413e41f113226b8a2e9b30bb519076d78e451fa0..d688339a57f0b4f12588ced0f7860a0d77eae728 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +@@ -52,10 +52,24 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + + @ItemMetaKey.Specific(ItemMetaKey.Specific.To.NBT) + static final ItemMetaKeyType BLOCK_ENTITY_TAG = new ItemMetaKeyType<>(DataComponents.BLOCK_ENTITY_DATA, "BlockEntityTag"); ++ static final ItemMetaKey BLOCK_ENTITY_TAG_CUSTOM_DATA = new ItemMetaKey("block-entity-tag"); // Paper ++ static final ItemMetaKey BLOCK_ENTITY_COMPONENTS = new ItemMetaKey("block-entity-components"); // Paper + + final Material material; +- private CraftBlockEntityState blockEntityTag; +- private BlockVector position; ++ // Paper start - store data separately ++ DataComponentMap components; ++ CustomData blockEntityTag; ++ { ++ // this is because the fields are possibly assigned in the super constructor (via deserializeInternal) ++ // and a direct field initialization happens **after** the super constructor. So we only want to ++ // set them to empty if they weren't assigned by the super constructor (via deserializeInternal) ++ this.components = this.components != null ? this.components : DataComponentMap.EMPTY; ++ this.blockEntityTag = this.blockEntityTag != null ? this.blockEntityTag : CustomData.EMPTY; ++ } ++ private Material materialForBlockEntityType() { ++ return this.material; ++ } ++ // Paper end + private CompoundTag internalTag; + + CraftMetaBlockState(CraftMetaItem meta, Material material) { +@@ -64,47 +78,61 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + + if (!(meta instanceof CraftMetaBlockState) + || ((CraftMetaBlockState) meta).material != material) { +- this.blockEntityTag = null; ++ // Paper start ++ this.components = DataComponentMap.EMPTY; ++ this.blockEntityTag = CustomData.EMPTY; ++ // Paper end + return; + } + + CraftMetaBlockState te = (CraftMetaBlockState) meta; ++ // Paper start ++ this.components = te.components; + this.blockEntityTag = te.blockEntityTag; +- this.position = te.position; ++ // Paper end + } + + CraftMetaBlockState(DataComponentPatch tag, Material material, final Set> extraHandledDcts) { // Paper + super(tag, extraHandledDcts); // Paper + this.material = material; + +- getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((blockTag) -> { +- CompoundTag nbt = blockTag.copyTag(); ++ // Paper start - move to separate method to be re-called ++ this.updateBlockState(tag); ++ } + +- this.blockEntityTag = CraftMetaBlockState.getBlockState(material, nbt); +- if (nbt.contains("x", CraftMagicNumbers.NBT.TAG_ANY_NUMBER) && nbt.contains("y", CraftMagicNumbers.NBT.TAG_ANY_NUMBER) && nbt.contains("z", CraftMagicNumbers.NBT.TAG_ANY_NUMBER)) { +- this.position = new BlockVector(nbt.getInt("x"), nbt.getInt("y"), nbt.getInt("z")); +- } ++ private void updateBlockState(final DataComponentPatch tag) { ++ // Paper end ++ getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((nbt) -> { ++ this.blockEntityTag = nbt; // Paper + }); + + if (!tag.isEmpty()) { +- CraftBlockEntityState blockEntityTag = this.blockEntityTag; +- if (blockEntityTag == null) { +- blockEntityTag = CraftMetaBlockState.getBlockState(material, null); +- } +- +- // Convert to map +- PatchedDataComponentMap map = new PatchedDataComponentMap(DataComponentMap.EMPTY); +- map.applyPatch(tag); +- // Apply +- Set> applied = blockEntityTag.applyComponents(map, tag); ++ // Paper start - store data in a DataComponentMap to be used to construct CraftBlockEntityStates ++ final DataComponentMap.Builder map = DataComponentMap.builder(); ++ final net.minecraft.world.level.block.entity.BlockEntity dummyBlockEntity = java.util.Objects.requireNonNull( ++ org.bukkit.craftbukkit.block.CraftBlockStates.createNewTileEntity(this.materialForBlockEntityType()) ++ ); ++ ++ // we don't care about what's in here, all ++ // we want is to know which data component types are referenced ++ Set> applied = dummyBlockEntity.applyComponentsSet(DataComponentMap.EMPTY, DataComponentPatch.EMPTY); ++ // Paper end - store data in a DataComponentMap to be used to construct CraftBlockEntityStates + // Mark applied components as handled + for (DataComponentType seen : applied) { + this.unhandledTags.clear(seen); + } + // Only set blockEntityTag if something was applied + if (!applied.isEmpty()) { +- this.blockEntityTag = blockEntityTag; ++ // Paper start ++ for (final DataComponentType type : applied) { ++ if (CraftMetaItem.DEFAULT_HANDLED_DCTS.contains(type)) continue; ++ getOrEmpty(tag, type).ifPresent(value -> { ++ map.set(type, value); ++ }); ++ } ++ // Paper end + } ++ this.components = map.build(); // Paper + } + } + +@@ -118,42 +146,43 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + this.material = Material.AIR; + } + if (this.internalTag != null) { +- this.blockEntityTag = CraftMetaBlockState.getBlockState(this.material, this.internalTag); ++ this.setBlockState(CraftMetaBlockState.getBlockState(this.material, this.internalTag)); // Paper - general item meta fixes - pass through setter + this.internalTag = null; + } +- this.position = SerializableMeta.getObject(BlockVector.class, map, "blockPosition", true); ++ // Paper start - general item meta fixes - parse spigot legacy position and merge into block entity tag ++ final BlockVector legacyPosition = SerializableMeta.getObject(BlockVector.class, map, "blockPosition", true); ++ if (legacyPosition != null) { ++ this.blockEntityTag = this.blockEntityTag.update(t -> { ++ if (t.isEmpty()) { ++ BlockEntity.addEntityType(t, java.util.Objects.requireNonNull(CraftBlockStates.getBlockEntityType(this.materialForBlockEntityType()))); ++ } ++ t.putInt("x", legacyPosition.getBlockX()); ++ t.putInt("y", legacyPosition.getBlockY()); ++ t.putInt("z", legacyPosition.getBlockZ()); ++ }); ++ } ++ // Paper end - general item meta fixes - parse spigot legacy position and merge into block entity tag + } + + @Override + void applyToItem(CraftMetaItem.Applicator tag) { + super.applyToItem(tag); + +- CompoundTag nbt = null; +- if (this.blockEntityTag != null) { +- nbt = this.blockEntityTag.getItemNBT(); +- +- for (TypedDataComponent component : this.blockEntityTag.collectComponents()) { +- tag.putIfAbsent(component); +- } ++ // Paper start - accurately replicate logic for creating ItemStack from BlockEntity ++ // taken from BlockEntity#saveToItem and BlockItem#setBlockEntityData ++ final CompoundTag nbt = this.blockEntityTag.copyTag(); ++ if (nbt.contains("id", CraftMagicNumbers.NBT.TAG_STRING)) { ++ tag.put(CraftMetaBlockState.BLOCK_ENTITY_TAG, CustomData.of(nbt)); ++ } else if (!nbt.isEmpty()) { ++ BlockEntity.addEntityType(nbt, java.util.Objects.requireNonNull(CraftBlockStates.getBlockEntityType(this.materialForBlockEntityType()))); ++ tag.put(CraftMetaBlockState.BLOCK_ENTITY_TAG, CustomData.of(nbt)); + } + +- if (this.position != null) { +- if (nbt == null) { +- nbt = new CompoundTag(); +- } +- +- nbt.putInt("x", this.position.getBlockX()); +- nbt.putInt("y", this.position.getBlockY()); +- nbt.putInt("z", this.position.getBlockZ()); +- } +- +- if (nbt != null && !nbt.isEmpty()) { +- CraftBlockEntityState tile = (this.blockEntityTag != null) ? this.blockEntityTag : CraftMetaBlockState.getBlockState(this.material, null); +- // See ItemBlock#setBlockEntityData +- tile.addEntityType(nbt); +- +- tag.put(CraftMetaBlockState.BLOCK_ENTITY_TAG, CustomData.of(nbt)); ++ for (final TypedDataComponent component : this.components) { ++ if (CraftMetaItem.DEFAULT_HANDLED_DCTS.contains(component.type())) continue; // if the component type was already handled by CraftMetaItem, don't add it again ++ tag.builder.set(component); + } ++ // Paper end + } + + @Override +@@ -162,23 +191,35 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + + if (tag.contains(CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { + this.internalTag = tag.getCompound(CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT); ++ return; // Paper - if legacy, don't check anything else ++ } ++ // Paper start - new serialization format ++ if (tag.contains(CraftMetaBlockState.BLOCK_ENTITY_TAG_CUSTOM_DATA.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { ++ this.blockEntityTag = CustomData.of(tag.getCompound(CraftMetaBlockState.BLOCK_ENTITY_TAG_CUSTOM_DATA.NBT)); ++ } ++ if (tag.contains(CraftMetaBlockState.BLOCK_ENTITY_COMPONENTS.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { ++ this.components = DataComponentMap.CODEC.parse(org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE), tag.getCompound(CraftMetaBlockState.BLOCK_ENTITY_COMPONENTS.NBT)).getOrThrow(); + } ++ // Paper end - new serialization format + } + + @Override + void serializeInternal(final Map internalTags) { +- if (this.blockEntityTag != null) { +- internalTags.put(CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT, this.blockEntityTag.getSnapshotNBT()); ++ // Paper start - new serialization format ++ if (!this.blockEntityTag.isEmpty()) { ++ internalTags.put(CraftMetaBlockState.BLOCK_ENTITY_TAG_CUSTOM_DATA.NBT, this.blockEntityTag.getUnsafe()); // unsafe because it's serialized right away + } ++ if (!this.components.isEmpty()) { ++ final Tag componentsTag = DataComponentMap.CODEC.encodeStart(org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE), this.components).getOrThrow(); ++ internalTags.put(CraftMetaBlockState.BLOCK_ENTITY_COMPONENTS.NBT, componentsTag); ++ } ++ // Paper end - new serialization format + } + + @Override + ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { + super.serialize(builder); + builder.put("blockMaterial", this.material.name()); +- if (this.position != null) { +- builder.put("blockPosition", this.position); +- } + return builder; + } + +@@ -186,12 +227,10 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + int applyHash() { + final int original; + int hash = original = super.applyHash(); +- if (this.blockEntityTag != null) { +- hash = 61 * hash + this.blockEntityTag.hashCode(); +- } +- if (this.position != null) { +- hash = 61 * hash + this.position.hashCode(); +- } ++ // Paper start ++ hash = 61 * hash + this.blockEntityTag.hashCode(); ++ hash = 61 * hash + this.components.hashCode(); ++ // Paper end + return original != hash ? CraftMetaBlockState.class.hashCode() ^ hash : hash; + } + +@@ -203,52 +242,75 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + if (meta instanceof CraftMetaBlockState) { + CraftMetaBlockState that = (CraftMetaBlockState) meta; + +- return Objects.equal(this.blockEntityTag, that.blockEntityTag) && Objects.equal(this.position, that.position); ++ return Objects.equal(this.blockEntityTag, that.blockEntityTag) && Objects.equal(this.components, that.components); // Paper + } + return true; + } + + boolean isBlockStateEmpty() { +- return !(this.blockEntityTag != null || this.position != null); ++ return !(this.blockEntityTag != null); + } + + @Override + boolean notUncommon(CraftMetaItem meta) { +- return super.notUncommon(meta) && (meta instanceof CraftMetaBlockState || this.isBlockStateEmpty()); ++ return super.notUncommon(meta) && (meta instanceof CraftMetaBlockState || (this.blockEntityTag.isEmpty() && this.components.isEmpty())); // Paper + } + + @Override + boolean isEmpty() { +- return super.isEmpty() && this.isBlockStateEmpty(); ++ return super.isEmpty() && this.blockEntityTag.isEmpty() && this.components.isEmpty(); // Paper + } + + @Override + public CraftMetaBlockState clone() { + CraftMetaBlockState meta = (CraftMetaBlockState) super.clone(); +- if (this.blockEntityTag != null) { +- meta.blockEntityTag = this.blockEntityTag.copy(); +- } +- if (this.position != null) { +- meta.position = this.position.clone(); +- } ++ // Paper start - no need for "clone" because they are essentially immutables ++ meta.blockEntityTag = this.blockEntityTag; ++ meta.components = this.components; ++ // Paper end + return meta; + } + + @Override + public boolean hasBlockState() { +- return this.blockEntityTag != null; ++ return !this.blockEntityTag.isEmpty() || !this.components.isEmpty(); // Paper + } + + // Paper start - add method to clear block state + @Override + public void clearBlockState() { +- this.blockEntityTag = null; ++ // Paper start ++ this.blockEntityTag = CustomData.EMPTY; ++ this.components = DataComponentMap.EMPTY; ++ // Paper end + } + // Paper end - add method to clear block state + + @Override +- public BlockState getBlockState() { +- return (this.blockEntityTag != null) ? this.blockEntityTag.copy() : CraftMetaBlockState.getBlockState(this.material, null); ++ // Paper start - create blockstate on-demand ++ public CraftBlockEntityState getBlockState() { ++ BlockPos pos = BlockPos.ZERO; ++ final Material stateMaterial = this.materialForBlockEntityType(); ++ if (!this.blockEntityTag.isEmpty()) { ++ // Paper "id" field is always present now ++ pos = BlockEntity.getPosFromTag(this.blockEntityTag.getUnsafe()); // unsafe is fine here, just querying ++ } ++ final net.minecraft.world.level.block.entity.BlockEntityType type = java.util.Objects.requireNonNull(CraftBlockStates.getBlockEntityType(stateMaterial)); ++ final net.minecraft.world.level.block.state.BlockState nmsBlockState = ((org.bukkit.craftbukkit.block.data.CraftBlockData) this.getBlockData(stateMaterial)).getState(); ++ final net.minecraft.world.level.block.entity.BlockEntity blockEntity = java.util.Objects.requireNonNull(type.create(pos, nmsBlockState)); ++ if (!this.blockEntityTag.isEmpty()) { ++ this.blockEntityTag.loadInto(blockEntity, org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry()); ++ } ++ final PatchedDataComponentMap patchedMap = new PatchedDataComponentMap(nmsBlockState.getBlock().asItem().components()); ++ patchedMap.setAll(this.components); ++ final Applicator applicator = new Applicator() {}; ++ super.applyToItem(applicator); ++ patchedMap.applyPatch(applicator.build()); ++ blockEntity.applyComponents(nmsBlockState.getBlock().asItem().components(), patchedMap.asPatch()); ++ ++ // This is expected to always return a CraftBlockEntityState for the passed material: ++ return (CraftBlockEntityState) CraftBlockStates.getBlockState(null, pos, nmsBlockState, blockEntity); ++ // Paper end + } + + private static CraftBlockEntityState getBlockState(Material material, CompoundTag blockEntityTag) { +@@ -278,7 +340,23 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + Class blockStateType = CraftBlockStates.getBlockStateType(stateMaterial); + Preconditions.checkArgument(blockStateType == blockState.getClass() && blockState instanceof CraftBlockEntityState, "Invalid blockState for %s", this.material); + +- this.blockEntityTag = (CraftBlockEntityState) blockState; ++ // Paper start - when a new BlockState is set, the components from that block entity ++ // have to be used to update the fields on CraftMetaItem ++ final CraftBlockEntityState craftBlockState = (CraftBlockEntityState) blockState; ++ final CompoundTag data = craftBlockState.getSnapshotCustomNbtOnly(); ++ final PatchedDataComponentMap patchedMap = new net.minecraft.core.component.PatchedDataComponentMap(craftBlockState.getHandle().getBlock().asItem().components()); ++ final net.minecraft.core.component.DataComponentMap map = craftBlockState.collectComponents(); ++ patchedMap.setAll(map); ++ if (!data.isEmpty()) { ++ patchedMap.set(BLOCK_ENTITY_TAG.TYPE, CustomData.of(data)); ++ } ++ final DataComponentPatch patch = patchedMap.asPatch(); ++ this.updateFromPatch(patch, null); ++ // we have to reset the fields because this should be like a "new" block entity is being used ++ this.blockEntityTag = CustomData.EMPTY; ++ this.components = DataComponentMap.EMPTY; ++ this.updateBlockState(patch); ++ // Paper end + } + + private static Material shieldToBannerHack(CompoundTag tag) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +index 257c835bc280eee9ee73ae75b5249bb568a687d0..70f20de37c1f8d57a8d9fe00dcd864fdd9948ec2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +@@ -34,7 +34,7 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta, WritableBo + @ItemMetaKey.Specific(ItemMetaKey.Specific.To.NBT) + static final ItemMetaKeyType BOOK_CONTENT = new ItemMetaKeyType<>(DataComponents.WRITABLE_BOOK_CONTENT); + static final ItemMetaKey BOOK_PAGES = new ItemMetaKey("pages"); +- static final int MAX_PAGES = Integer.MAX_VALUE; // SPIGOT-6911: Use Minecraft limits ++ static final int MAX_PAGES = WritableBookContent.MAX_PAGES; // SPIGOT-6911: Use Minecraft limits // Paper + static final int MAX_PAGE_LENGTH = WritableBookContent.PAGE_EDIT_LENGTH; // SPIGOT-6911: Use Minecraft limits + + // We store the pages in their raw original text representation. See SPIGOT-5063, SPIGOT-5350, SPIGOT-3206 +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java +index cbb3d80cc7cd81b2505dff999a0baede737165f7..040dac82e484cb44b3afd444b4bbd1fd994bfe7c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java +@@ -124,13 +124,13 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta { + void applyToItem(CraftMetaItem.Applicator itemData) { + super.applyToItem(itemData); + ++ List> list = new ArrayList<>(); // Paper - General ItemMeta Fixes + if (this.pages != null) { +- List> list = new ArrayList<>(); + for (Component page : this.pages) { + list.add(Filterable.passThrough(page)); + } +- itemData.put(CraftMetaBookSigned.BOOK_CONTENT, new WrittenBookContent(Filterable.from(FilteredText.passThrough(this.title)), this.author, this.generation, list, this.resolved)); + } ++ itemData.put(CraftMetaBookSigned.BOOK_CONTENT, new WrittenBookContent(Filterable.from(this.title == null ? FilteredText.EMPTY : FilteredText.passThrough(this.title)), this.author == null ? "" : this.author, this.generation, list, this.resolved)); // Paper - General ItemMeta Fixes + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java +index 2736a87a6c481da0575e6e29ea08faa539c24378..51da0db4da3549efd69f367e28450408968fa8d0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java +@@ -41,7 +41,7 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { + bundle.items().forEach((item) -> { + ItemStack itemStack = CraftItemStack.asCraftMirror(item); + +- if (!itemStack.getType().isAir()) { // SPIGOT-7174 - Avoid adding air ++ if (!itemStack.isEmpty()) { // SPIGOT-7174 - Avoid adding air // Paper + this.addItem(itemStack); + } + }); +@@ -54,7 +54,7 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { + Iterable items = SerializableMeta.getObject(Iterable.class, map, CraftMetaBundle.ITEMS.BUKKIT, true); + if (items != null) { + for (Object stack : items) { +- if (stack instanceof ItemStack itemStack && !itemStack.getType().isAir()) { // SPIGOT-7174 - Avoid adding air ++ if (stack instanceof ItemStack itemStack && !itemStack.isEmpty()) { // SPIGOT-7174 - Avoid adding air // Paper + this.addItem(itemStack); + } + } +@@ -110,7 +110,7 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { + + @Override + public void addItem(ItemStack item) { +- Preconditions.checkArgument(item != null && !item.getType().isAir(), "item is null or air"); ++ Preconditions.checkArgument(item != null && !item.isEmpty(), "item is null or empty"); // Paper + + if (this.items == null) { + this.items = new ArrayList<>(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +index dc6398cfbd6e749733c3a681e1eb8ce15c3b2c5e..51d7263cdd34359d9cdf72cc01ba654b519f838d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +@@ -11,16 +11,30 @@ import org.bukkit.inventory.meta.ColorableArmorMeta; + @DelegateDeserialization(SerializableMeta.class) + public class CraftMetaColorableArmor extends CraftMetaArmor implements ColorableArmorMeta { + +- private Color color = DEFAULT_LEATHER_COLOR; ++ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) + + CraftMetaColorableArmor(CraftMetaItem meta) { + super(meta); +- CraftMetaLeatherArmor.readColor(this, meta); ++ // Paper start ++ if (!(meta instanceof CraftMetaColorableArmor armorMeta)) { ++ return; ++ } ++ ++ this.color = armorMeta.color; ++ // Paper end + } + + CraftMetaColorableArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper + super(tag, extraHandledDcts); // Paper +- CraftMetaLeatherArmor.readColor(this, tag); ++ // Paper start ++ getOrEmpty(tag, CraftMetaLeatherArmor.COLOR).ifPresent((dyedItemColor) -> { ++ if (!dyedItemColor.showInTooltip()) { ++ this.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_DYE); ++ } ++ ++ this.color = dyedItemColor.rgb(); ++ }); ++ // Paper end + } + + CraftMetaColorableArmor(Map map) { +@@ -31,7 +45,11 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable + @Override + void applyToItem(CraftMetaItem.Applicator itemTag) { + super.applyToItem(itemTag); +- CraftMetaLeatherArmor.applyColor(this, itemTag); ++ // Paper start ++ if (this.hasColor()) { ++ itemTag.put(CraftMetaLeatherArmor.COLOR, new net.minecraft.world.item.component.DyedItemColor(this.color, !this.hasItemFlag(org.bukkit.inventory.ItemFlag.HIDE_DYE))); ++ } ++ // Paper end + } + + @Override +@@ -52,16 +70,16 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable + + @Override + public Color getColor() { +- return this.color; ++ return this.color == null ? DEFAULT_LEATHER_COLOR : Color.fromRGB(this.color & 0xFFFFFF); // Paper - this should really be nullable + } + + @Override + public void setColor(Color color) { +- this.color = color == null ? DEFAULT_LEATHER_COLOR : color; ++ this.color = color == null ? null : color.asRGB(); // Paper + } + + boolean hasColor() { +- return CraftMetaLeatherArmor.hasColor(this); ++ return this.color != null; // Paper + } + + @Override +@@ -81,7 +99,7 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable + if (meta instanceof CraftMetaColorableArmor) { + CraftMetaColorableArmor that = (CraftMetaColorableArmor) meta; + +- return this.color.equals(that.color); ++ return this.hasColor() ? that.hasColor() && this.color.equals(that.color) : !that.hasColor(); // Paper - allow null + } + return true; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java +index 69a112b3a9726966aecbe687d905fd1a11cfa1e3..ab424926c282fb03eabd1eebd2b7980899ef28e3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java +@@ -31,11 +31,7 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + static final ItemMetaKey LODESTONE_POS_Z = new ItemMetaKey("LodestonePosZ"); + static final ItemMetaKey LODESTONE_TRACKED = new ItemMetaKey("LodestoneTracked"); + +- private ResourceKey lodestoneWorld; +- private int lodestoneX; +- private int lodestoneY; +- private int lodestoneZ; +- private boolean tracked = true; ++ private LodestoneTracker tracker; // Paper - use LodestoneTracker type + + CraftMetaCompass(CraftMetaItem meta) { + super(meta); +@@ -43,24 +39,13 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + return; + } + CraftMetaCompass compassMeta = (CraftMetaCompass) meta; +- this.lodestoneWorld = compassMeta.lodestoneWorld; +- this.lodestoneX = compassMeta.lodestoneX; +- this.lodestoneY = compassMeta.lodestoneY; +- this.lodestoneZ = compassMeta.lodestoneZ; +- this.tracked = compassMeta.tracked; ++ this.tracker = compassMeta.tracker; // Paper - use LodestoneTracker type + } + + CraftMetaCompass(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper + super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaCompass.LODESTONE_TARGET).ifPresent((lodestoneTarget) -> { +- lodestoneTarget.target().ifPresent((target) -> { +- this.lodestoneWorld = target.dimension(); +- BlockPos pos = target.pos(); +- this.lodestoneX = pos.getX(); +- this.lodestoneY = pos.getY(); +- this.lodestoneZ = pos.getZ(); +- }); +- this.tracked = lodestoneTarget.tracked(); ++ this.tracker = lodestoneTarget; // Paper - use LodestoneTracker type + }); + } + +@@ -68,10 +53,13 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + super(map); + String lodestoneWorldString = SerializableMeta.getString(map, CraftMetaCompass.LODESTONE_POS_WORLD.BUKKIT, true); + if (lodestoneWorldString != null) { +- this.lodestoneWorld = ResourceKey.create(Registries.DIMENSION, ResourceLocation.tryParse(lodestoneWorldString)); +- this.lodestoneX = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_X.BUKKIT); +- this.lodestoneY = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT); +- this.lodestoneZ = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT); ++ // Paper start - use LodestoneTracker type ++ ResourceKey lodestoneWorld = ResourceKey.create(Registries.DIMENSION, ResourceLocation.tryParse(lodestoneWorldString)); ++ int lodestoneX = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_X.BUKKIT); ++ int lodestoneY = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT); ++ int lodestoneZ = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT); ++ this.tracker = new LodestoneTracker(Optional.of(new GlobalPos(lodestoneWorld, new BlockPos(lodestoneX, lodestoneY, lodestoneZ))), true); ++ // Paper end - use LodestoneTracker type + } else { + // legacy + Location lodestone = SerializableMeta.getObject(Location.class, map, CraftMetaCompass.LODESTONE_POS.BUKKIT, true); +@@ -79,21 +67,22 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + this.setLodestone(lodestone); + } + } +- this.tracked = SerializableMeta.getBoolean(map, CraftMetaCompass.LODESTONE_TRACKED.BUKKIT); ++ // Paper start - use LodestoneTracker type ++ final Optional tracked = SerializableMeta.getObjectOptionally(Boolean.class, map, CraftMetaCompass.LODESTONE_TRACKED.BUKKIT, true); ++ final Optional trackedPos = this.tracker != null ? this.tracker.target() : Optional.empty(); ++ tracked.ifPresent(isTracked -> this.tracker = new LodestoneTracker(trackedPos, isTracked)); ++ // Paper end - use LodestoneTracker type + } + + @Override + void applyToItem(CraftMetaItem.Applicator tag) { + super.applyToItem(tag); + +- Optional target = Optional.empty(); +- if (this.lodestoneWorld != null) { +- target = Optional.of(new GlobalPos(this.lodestoneWorld, new BlockPos(this.lodestoneX, this.lodestoneY, this.lodestoneZ))); +- } +- +- if (target.isPresent() || this.hasLodestoneTracked()) { +- tag.put(CraftMetaCompass.LODESTONE_TARGET, new LodestoneTracker(target, this.tracked)); ++ // Paper start - use LodestoneTracker type ++ if (this.tracker != null) { ++ tag.put(CraftMetaCompass.LODESTONE_TARGET, this.tracker); + } ++ // Paper end - use LodestoneTracker type + } + + @Override +@@ -102,7 +91,7 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + } + + boolean isCompassEmpty() { +- return !(this.hasLodestone() || this.hasLodestoneTracked()); ++ return this.tracker == null; // Paper - use LodestoneTracker type + } + + @Override +@@ -113,58 +102,69 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + + @Override + public boolean hasLodestone() { +- return this.lodestoneWorld != null; ++ return this.tracker != null && this.tracker.target().isPresent(); // Paper - use LodestoneTracker type + } + + @Override + public Location getLodestone() { +- if (this.lodestoneWorld == null) { ++ if (this.tracker == null || this.tracker.target().isEmpty()) { // Paper - use LodestoneTracker type + return null; + } +- ServerLevel worldServer = MinecraftServer.getServer().getLevel(this.lodestoneWorld); ++ ServerLevel worldServer = MinecraftServer.getServer().getLevel(this.tracker.target().get().dimension()); // Paper - use LodestoneTracker type + World world = worldServer != null ? worldServer.getWorld() : null; +- return new Location(world, this.lodestoneX, this.lodestoneY, this.lodestoneZ); // world may be null here, if the referenced world is not loaded ++ return org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.tracker.target().get().pos(), world); // world may be null here, if the referenced world is not loaded // Paper - use LodestoneTracker type + } + + @Override + public void setLodestone(Location lodestone) { + Preconditions.checkArgument(lodestone == null || lodestone.getWorld() != null, "world is null"); + if (lodestone == null) { +- this.lodestoneWorld = null; ++ // Paper start - use LodestoneTracker type ++ if (this.tracker != null) { ++ this.tracker = new LodestoneTracker(java.util.Optional.empty(), this.tracker.tracked()); // Paper - use LodestoneTracker type ++ } ++ // Paper end - use LodestoneTracker type + } else { +- this.lodestoneWorld = ((CraftWorld) lodestone.getWorld()).getHandle().dimension(); +- this.lodestoneX = lodestone.getBlockX(); +- this.lodestoneY = lodestone.getBlockY(); +- this.lodestoneZ = lodestone.getBlockZ(); ++ // Paper start - use LodestoneTracker type ++ GlobalPos pos = GlobalPos.of( ++ ((CraftWorld) lodestone.getWorld()).getHandle().dimension(), ++ io.papermc.paper.util.MCUtil.toBlockPosition(lodestone) ++ ); ++ boolean tracked = this.tracker == null || this.tracker.tracked(); ++ this.tracker = new LodestoneTracker(Optional.of(pos), tracked); ++ // Paper end - use LodestoneTracker type + } + } + +- boolean hasLodestoneTracked() { +- return !this.tracked; +- } +- + @Override + public boolean isLodestoneTracked() { +- return this.tracked; ++ return this.tracker != null && this.tracker.tracked(); // Paper - use LodestoneTracker type + } + + @Override + public void setLodestoneTracked(boolean tracked) { +- this.tracked = tracked; ++ final Optional trackedPos = this.tracker != null ? this.tracker.target() : Optional.empty(); // Paper - use LodestoneTracker type ++ this.tracker = new LodestoneTracker(trackedPos, tracked); // Paper - use LodestoneTracker type ++ } ++ ++ // Paper start - Add more lodestone compass methods ++ @Override ++ public boolean isLodestoneCompass() { ++ return this.tracker != null; ++ } ++ ++ @Override ++ public void clearLodestone() { ++ this.tracker = null; + } ++ // Paper end - Add more lodestone compass methods + + @Override + int applyHash() { + final int original; + int hash = original = super.applyHash(); +- if (this.hasLodestone()) { +- hash = 73 * hash + this.lodestoneWorld.hashCode(); +- hash = 73 * hash + this.lodestoneX; +- hash = 73 * hash + this.lodestoneY; +- hash = 73 * hash + this.lodestoneZ; +- } +- if (this.hasLodestoneTracked()) { +- hash = 73 * hash + (this.isLodestoneTracked() ? 1231 : 1237); ++ if (this.isLodestoneCompass()) { ++ hash = 73 * hash + this.tracker.hashCode(); // Paper - use LodestoneTracker type + } + + return original != hash ? CraftMetaCompass.class.hashCode() ^ hash : hash; +@@ -178,10 +178,7 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + if (meta instanceof CraftMetaCompass) { + CraftMetaCompass that = (CraftMetaCompass) meta; + +- return (this.hasLodestone() ? that.hasLodestone() && this.lodestoneWorld.equals(that.lodestoneWorld) +- && this.lodestoneX == that.lodestoneX && this.lodestoneY == that.lodestoneY +- && this.lodestoneZ == that.lodestoneZ : !that.hasLodestone()) +- && this.tracked == that.tracked; ++ return java.util.Objects.equals(this.tracker, that.tracker); // Paper - use LodestoneTracker type + } + return true; + } +@@ -195,14 +192,16 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + Builder serialize(Builder builder) { + super.serialize(builder); + +- if (this.hasLodestone()) { +- builder.put(CraftMetaCompass.LODESTONE_POS_WORLD.BUKKIT, this.lodestoneWorld.location().toString()); +- builder.put(CraftMetaCompass.LODESTONE_POS_X.BUKKIT, this.lodestoneX); +- builder.put(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT, this.lodestoneY); +- builder.put(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT, this.lodestoneZ); +- } +- if (this.hasLodestoneTracked()) { +- builder.put(CraftMetaCompass.LODESTONE_TRACKED.BUKKIT, this.tracked); ++ if (this.isLodestoneCompass()) { // Paper - use LodestoneTracker type ++ // Paper start - use LodestoneTracker type ++ if (this.tracker.target().isPresent()) { ++ builder.put(CraftMetaCompass.LODESTONE_POS_WORLD.BUKKIT, this.tracker.target().get().dimension().location().toString()); ++ builder.put(CraftMetaCompass.LODESTONE_POS_X.BUKKIT, this.tracker.target().get().pos().getX()); ++ builder.put(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT, this.tracker.target().get().pos().getY()); ++ builder.put(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT, this.tracker.target().get().pos().getZ()); ++ } ++ builder.put(CraftMetaCompass.LODESTONE_TRACKED.BUKKIT, this.tracker.tracked()); ++ // Paper end - use LodestoneTracker type + } + + return builder; +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java +index 0807c2172c5a4bee675cef265a45a9350e98b880..88ea260fb84a5f8eaab3a23a9a65d0411215a6a1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java +@@ -117,7 +117,7 @@ public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta { + @Override + public void addChargedProjectile(ItemStack item) { + Preconditions.checkArgument(item != null, "item"); +- Preconditions.checkArgument(item.getType() == Material.FIREWORK_ROCKET || CraftItemType.bukkitToMinecraft(item.getType()) instanceof ArrowItem, "Item %s is not an arrow or firework rocket", item); ++ Preconditions.checkArgument(!item.isEmpty(), "Item cannot be empty"); // Paper + + if (this.chargedProjectiles == null) { + this.chargedProjectiles = new ArrayList<>(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +index 3f6c5cbbf63631e4b72dc43558651ea94f31ca78..da474a5b963d8e6769d120e9091e60ed0a468a9f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +@@ -98,7 +98,7 @@ public class CraftMetaEntityTag extends CraftMetaItem { + if (meta instanceof CraftMetaEntityTag) { + CraftMetaEntityTag that = (CraftMetaEntityTag) meta; + +- return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : this.entityTag == null; ++ return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : that.entityTag == null; // Paper + } + return true; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +index 566d893a413fd04b99e83dc2da8fe958a48492a8..a944803771d514572f94b4e98a6d4435a009c078 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +@@ -55,7 +55,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + + this.power = that.power; + +- if (that.hasEffects()) { ++ if (that.effects != null) { // Paper + this.effects = new ArrayList<>(that.effects); + } + } +@@ -88,7 +88,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + } + + Iterable effects = SerializableMeta.getObject(Iterable.class, map, CraftMetaFirework.EXPLOSIONS.BUKKIT, true); +- this.safelyAddEffects(effects); ++ this.safelyAddEffects(effects, false); // Paper - limit firework effects + } + + static FireworkEffect getEffect(FireworkExplosion explosion) { +@@ -98,19 +98,14 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + .with(CraftMetaFirework.getEffectType(explosion.shape())); + + IntList colors = explosion.colors(); +- // People using buggy command generators specify a list rather than an int here, so recover with dummy data. +- // Wrong: Colors: [1234] +- // Right: Colors: [I;1234] +- if (colors.isEmpty()) { +- effect.withColor(Color.WHITE); +- } ++ // Paper - this is no longer needed + + for (int color : colors) { +- effect.withColor(Color.fromRGB(color)); ++ effect.withColor(Color.fromRGB(color & 0xFFFFFF)); // Paper - try to keep color component consistent with vanilla (top byte is ignored), this will however change the color component for out of bound color + } + + for (int color : explosion.fadeColors()) { +- effect.withFade(Color.fromRGB(color)); ++ effect.withFade(Color.fromRGB(color & 0xFFFFFF)); // Paper + } + + return effect.build(); +@@ -162,7 +157,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + return !(this.effects == null || this.effects.isEmpty()); + } + +- void safelyAddEffects(Iterable collection) { ++ void safelyAddEffects(Iterable collection, final boolean throwOnOversize) { // Paper + if (collection == null || (collection instanceof Collection && ((Collection) collection).isEmpty())) { + return; + } +@@ -174,6 +169,15 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + + for (Object obj : collection) { + Preconditions.checkArgument(obj instanceof FireworkEffect, "%s in %s is not a FireworkEffect", obj, collection); ++ // Paper start - limit firework effects ++ if (effects.size() + 1 > Fireworks.MAX_EXPLOSIONS) { ++ if (throwOnOversize) { ++ throw new IllegalArgumentException("Cannot have more than " + Fireworks.MAX_EXPLOSIONS + " firework effects"); ++ } else { ++ continue; ++ } ++ } ++ // Paper end - limit firework effects + effects.add((FireworkEffect) obj); + } + } +@@ -215,7 +219,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + } + + boolean isFireworkEmpty() { +- return !(this.hasEffects() || this.hasPower()); ++ return !(this.effects != null || this.hasPower()); // Paper - empty effects list should stay on the item + } + + @Override +@@ -232,7 +236,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + if (meta instanceof CraftMetaFirework that) { + + return (Objects.equals(this.power, that.power)) +- && (this.hasEffects() ? that.hasEffects() && this.effects.equals(that.effects) : !that.hasEffects()); ++ && (this.effects != null ? that.effects != null && this.effects.equals(that.effects) : that.effects == null); // Paper + } + + return true; +@@ -250,7 +254,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + if (this.hasPower()) { + hash = 61 * hash + this.power; + } +- if (this.hasEffects()) { ++ if (this.effects != null) { // Paper + hash = 61 * hash + 13 * this.effects.hashCode(); + } + return hash != original ? CraftMetaFirework.class.hashCode() ^ hash : hash; +@@ -260,7 +264,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + Builder serialize(Builder builder) { + super.serialize(builder); + +- if (this.hasEffects()) { ++ if (this.effects != null) { // Paper + builder.put(CraftMetaFirework.EXPLOSIONS.BUKKIT, ImmutableList.copyOf(this.effects)); + } + +@@ -285,6 +289,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + @Override + public void addEffect(FireworkEffect effect) { + Preconditions.checkArgument(effect != null, "FireworkEffect cannot be null"); ++ Preconditions.checkArgument(this.effects == null || this.effects.size() + 1 <= Fireworks.MAX_EXPLOSIONS, "cannot have more than %s firework effects", Fireworks.MAX_EXPLOSIONS); // Paper - limit firework effects + if (this.effects == null) { + this.effects = new ArrayList(); + } +@@ -294,6 +299,10 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + @Override + public void addEffects(FireworkEffect... effects) { + Preconditions.checkArgument(effects != null, "effects cannot be null"); ++ // Paper start - limit firework effects ++ final int initialSize = this.effects == null ? 0 : this.effects.size(); ++ Preconditions.checkArgument(initialSize + effects.length <= Fireworks.MAX_EXPLOSIONS, "Cannot have more than %s firework effects", Fireworks.MAX_EXPLOSIONS); ++ // Paper end - limit firework effects + if (effects.length == 0) { + return; + } +@@ -312,7 +321,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + @Override + public void addEffects(Iterable effects) { + Preconditions.checkArgument(effects != null, "effects cannot be null"); +- this.safelyAddEffects(effects); ++ this.safelyAddEffects(effects, true); // Paper - limit firework effects + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 13b19adc21ece31476b2980c5bc01a50f15df634..a6e2281bfac94f1e19836d9c8415d8270387b16d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -199,9 +199,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + } + +- static final class Applicator { ++ static abstract class Applicator { // Paper - support updating profile after resolving it + +- private final DataComponentPatch.Builder builder = DataComponentPatch.builder(); ++ final DataComponentPatch.Builder builder = DataComponentPatch.builder(); // Paper - private -> package-private ++ void skullCallback(net.minecraft.world.item.component.ResolvableProfile resolvableProfile) {} // Paper - support updating profile after resolving it + + Applicator put(ItemMetaKeyType key, T value) { + this.builder.set(key.TYPE, value); +@@ -308,7 +309,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + private CraftToolComponent tool; + private CraftEquippableComponent equippable; + private CraftJukeboxComponent jukebox; +- private int damage; ++ private Integer damage; // Paper - may not be set + private Integer maxDamage; + + private static final Set HANDLED_TAGS = Sets.newHashSet(); +@@ -341,7 +342,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.enchantments = new EnchantmentMap(meta.enchantments); // Paper + } + +- if (meta.hasAttributeModifiers()) { ++ if (meta.attributeModifiers != null) { // Paper + this.attributeModifiers = LinkedHashMultimap.create(meta.attributeModifiers); + } + +@@ -390,6 +391,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + + CraftMetaItem(DataComponentPatch tag, Set> extraHandledTags) { // Paper - improve handled tags on type changes ++ // Paper start - properly support data components in BlockEntity ++ this.updateFromPatch(tag, extraHandledTags); ++ } ++ protected final void updateFromPatch(DataComponentPatch tag, Set> extraHandledTags) { ++ // Paper end - properly support data components in BlockEntity + CraftMetaItem.getOrEmpty(tag, CraftMetaItem.NAME).ifPresent((component) -> { + this.displayName = component; + }); +@@ -906,7 +912,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + Map mods = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true); + Multimap result = LinkedHashMultimap.create(); + if (mods == null) { +- return result; ++ return null; // Paper - null is different from an empty map + } + + for (Object obj : mods.keySet()) { +@@ -1037,7 +1043,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + itemTag.put(CraftMetaItem.JUKEBOX_PLAYABLE, this.jukebox.getHandle()); + } + +- if (this.hasDamage()) { ++ if (this.hasDamageValue()) { // Paper - preserve empty/0 damage + itemTag.put(CraftMetaItem.DAMAGE, this.damage); + } + +@@ -1087,7 +1093,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + + void applyEnchantments(Map enchantments, CraftMetaItem.Applicator tag, ItemMetaKeyType key, ItemFlag itemFlag) { +- if (enchantments == null && !this.hasItemFlag(itemFlag)) { ++ if (enchantments == null /*&& !this.hasItemFlag(itemFlag)*/) { // Paper - general item meta fixes - only emit enchantment component if enchantments are defined + return; + } + +@@ -1104,10 +1110,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + + void applyModifiers(Multimap modifiers, CraftMetaItem.Applicator tag) { +- if (modifiers == null || modifiers.isEmpty()) { +- if (this.hasItemFlag(ItemFlag.HIDE_ATTRIBUTES)) { +- tag.put(CraftMetaItem.ATTRIBUTES, new ItemAttributeModifiers(Collections.emptyList(), false)); +- } ++ if (modifiers == null/* || modifiers.isEmpty()*/) { // Paper - empty modifiers has a specific meaning, they should still be saved ++ // Paper - don't save ItemFlag if the underlying data isn't present + return; + } + +@@ -1144,7 +1148,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Overridden + boolean isEmpty() { +- return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper ++ return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamageValue() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper + } + + // Paper start +@@ -1240,6 +1244,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public void lore(final List lore) { ++ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines + this.lore = lore != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(lore) : null; + } + // Paper end +@@ -1298,7 +1303,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + @Override + public void removeEnchantments() { + if (this.hasEnchants()) { +- this.enchantments.clear(); ++ this.enchantments = null; // Paper - Correctly clear enchantments + } + } + +@@ -1364,6 +1369,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + // Paper end + @Override + public void setLore(List lore) { ++ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines + if (lore == null || lore.isEmpty()) { + this.lore = null; + } else { +@@ -1379,6 +1385,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + // Paper start + @Override + public void setLoreComponents(List lore) { ++ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines + if (lore == null) { + this.lore = null; + } else { +@@ -1596,6 +1603,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public void setUseRemainder(ItemStack useRemainder) { ++ Preconditions.checkArgument(useRemainder == null || !useRemainder.isEmpty(), "Item cannot be empty"); // Paper + this.useRemainder = useRemainder; + } + +@@ -1606,7 +1614,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public UseCooldownComponent getUseCooldown() { +- return (this.hasUseCooldown()) ? new CraftUseCooldownComponent(this.useCooldown) : new CraftUseCooldownComponent(new UseCooldown(0)); ++ return (this.hasUseCooldown()) ? new CraftUseCooldownComponent(this.useCooldown) : new CraftUseCooldownComponent(new UseCooldown(1.0F)); // Paper - Create a valid use_cooldown component + } + + @Override +@@ -1656,7 +1664,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public void setEquippable(EquippableComponent equippable) { +- this.equippable = (equippable == null) ? null : new CraftEquippableComponent((CraftEquippableComponent) this.equippable); ++ this.equippable = (equippable == null) ? null : new CraftEquippableComponent((CraftEquippableComponent) equippable); // Paper + } + + @Override +@@ -1692,7 +1700,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public Multimap getAttributeModifiers(@Nullable EquipmentSlot slot) { +- this.checkAttributeList(); ++ if (this.attributeModifiers == null) return LinkedHashMultimap.create(); // Paper - don't change the components + SetMultimap result = LinkedHashMultimap.create(); + for (Map.Entry entry : this.attributeModifiers.entries()) { + if (entry.getValue().getSlot() == null || entry.getValue().getSlot() == slot) { +@@ -1705,6 +1713,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + @Override + public Collection getAttributeModifiers(@Nonnull Attribute attribute) { + Preconditions.checkNotNull(attribute, "Attribute cannot be null"); ++ if (this.attributeModifiers == null) return null; // Paper - fix NPE + return this.attributeModifiers.containsKey(attribute) ? ImmutableList.copyOf(this.attributeModifiers.get(attribute)) : null; + } + +@@ -1712,22 +1721,33 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + public boolean addAttributeModifier(@Nonnull Attribute attribute, @Nonnull AttributeModifier modifier) { + Preconditions.checkNotNull(attribute, "Attribute cannot be null"); + Preconditions.checkNotNull(modifier, "AttributeModifier cannot be null"); +- this.checkAttributeList(); ++ if (this.attributeModifiers != null) { // Paper + for (Map.Entry entry : this.attributeModifiers.entries()) { + Preconditions.checkArgument(!(entry.getValue().getKey().equals(modifier.getKey()) && entry.getKey() == attribute), "Cannot register AttributeModifier. Modifier is already applied! %s", modifier); // Paper - attribute modifiers with same namespaced key but on different attributes are fine + } ++ } // Paper ++ this.checkAttributeList(); // Paper - moved down + return this.attributeModifiers.put(attribute, modifier); + } + + @Override + public void setAttributeModifiers(@Nullable Multimap attributeModifiers) { +- if (attributeModifiers == null || attributeModifiers.isEmpty()) { ++ // Paper start - distinguish between null and empty ++ if (attributeModifiers == null) { ++ this.attributeModifiers = null; ++ return; ++ } ++ if (attributeModifiers.isEmpty()) { ++ // Paper end - distinguish between null and empty + this.attributeModifiers = LinkedHashMultimap.create(); + return; + } + +- this.checkAttributeList(); +- this.attributeModifiers.clear(); ++ // Paper start - fix modifiers meta ++ if (this.attributeModifiers != null) { ++ this.attributeModifiers.clear(); ++ } ++ // Paper end + + Iterator> iterator = attributeModifiers.entries().iterator(); + while (iterator.hasNext()) { +@@ -1737,6 +1757,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + iterator.remove(); + continue; + } ++ this.checkAttributeList(); // Paper - moved down + this.attributeModifiers.put(next.getKey(), next.getValue()); + } + } +@@ -1744,13 +1765,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + @Override + public boolean removeAttributeModifier(@Nonnull Attribute attribute) { + Preconditions.checkNotNull(attribute, "Attribute cannot be null"); +- this.checkAttributeList(); ++ if (this.attributeModifiers == null) return false; // Paper + return !this.attributeModifiers.removeAll(attribute).isEmpty(); + } + + @Override + public boolean removeAttributeModifier(@Nullable EquipmentSlot slot) { +- this.checkAttributeList(); ++ if (this.attributeModifiers == null) return false; // Paper + int removed = 0; + Iterator> iter = this.attributeModifiers.entries().iterator(); + +@@ -1770,7 +1791,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + public boolean removeAttributeModifier(@Nonnull Attribute attribute, @Nonnull AttributeModifier modifier) { + Preconditions.checkNotNull(attribute, "Attribute cannot be null"); + Preconditions.checkNotNull(modifier, "AttributeModifier cannot be null"); +- this.checkAttributeList(); ++ if (this.attributeModifiers == null) return false; // Paper + int removed = 0; + Iterator> iter = this.attributeModifiers.entries().iterator(); + +@@ -1792,7 +1813,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public String getAsString() { +- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); ++ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {}; // Paper - support updating profile after resolving it + this.applyToItem(tag); + DataComponentPatch patch = tag.build(); + net.minecraft.nbt.Tag nbt = DataComponentPatch.CODEC.encodeStart(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), patch).getOrThrow(); +@@ -1801,7 +1822,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public String getAsComponentString() { +- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); ++ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {}; // Paper + this.applyToItem(tag); + DataComponentPatch patch = tag.build(); + +@@ -1841,6 +1862,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + if (first == null || second == null) { + return false; + } ++ if (first.isEmpty() && second.isEmpty()) return true; // Paper - empty modifiers are equivalent + for (Map.Entry entry : first.entries()) { + if (!second.containsEntry(entry.getKey(), entry.getValue())) { + return false; +@@ -1856,19 +1878,33 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public boolean hasDamage() { +- return this.damage > 0; ++ return this.damage != null && this.damage > 0; // Paper - null check + } + + @Override + public int getDamage() { +- return this.damage; ++ return this.damage == null ? 0 : this.damage; // Paper - null check + } + + @Override + public void setDamage(int damage) { ++ Preconditions.checkArgument(damage >= 0, "Damage cannot be negative"); // Paper ++ Preconditions.checkArgument(!this.hasMaxDamage() || damage <= this.maxDamage, "Damage cannot exceed max damage"); // Paper + this.damage = damage; + } + ++ // Paper start - preserve empty/0 damage ++ @Override ++ public boolean hasDamageValue() { ++ return this.damage != null; ++ } ++ ++ @Override ++ public void resetDamage() { ++ this.damage = null; ++ } ++ // Paper end - preserve empty/0 damage ++ + @Override + public boolean hasMaxDamage() { + return this.maxDamage != null; +@@ -1882,6 +1918,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public void setMaxDamage(Integer maxDamage) { ++ Preconditions.checkArgument(maxDamage == null || maxDamage > 0, "Max damage should be positive"); // Paper + this.maxDamage = maxDamage; + } + +@@ -1914,7 +1951,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + && (this.hasEnchantable() ? that.hasEnchantable() && this.enchantableValue.equals(that.enchantableValue) : !that.hasEnchantable()) + && (this.hasBlockData() ? that.hasBlockData() && this.blockData.equals(that.blockData) : !that.hasBlockData()) + && (this.hasRepairCost() ? that.hasRepairCost() && this.repairCost == that.repairCost : !that.hasRepairCost()) +- && (this.hasAttributeModifiers() ? that.hasAttributeModifiers() && CraftMetaItem.compareModifiers(this.attributeModifiers, that.attributeModifiers) : !that.hasAttributeModifiers()) ++ && (this.attributeModifiers != null ? that.attributeModifiers != null && CraftMetaItem.compareModifiers(this.attributeModifiers, that.attributeModifiers) : that.attributeModifiers == null) // Paper - track only null modifiers + && (this.unhandledTags.equals(that.unhandledTags)) + && (this.removedTags.equals(that.removedTags)) + && (Objects.equals(this.customTag, that.customTag)) +@@ -1935,7 +1972,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + && (this.hasTool() ? that.hasTool() && this.tool.equals(that.tool) : !that.hasTool()) + && (this.hasEquippable() ? that.hasEquippable() && this.equippable.equals(that.equippable) : !that.hasEquippable()) + && (this.hasJukeboxPlayable() ? that.hasJukeboxPlayable() && this.jukebox.equals(that.jukebox) : !that.hasJukeboxPlayable()) +- && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) ++ && (Objects.equals(this.damage, that.damage)) // Paper - preserve empty/0 damage + && (this.hasMaxDamage() ? that.hasMaxDamage() && this.maxDamage.equals(that.maxDamage) : !that.hasMaxDamage()) + && (this.canPlaceOnPredicates != null ? that.canPlaceOnPredicates != null && this.canPlaceOnPredicates.equals(that.canPlaceOnPredicates) : that.canPlaceOnPredicates == null) // Paper + && (this.canBreakPredicates != null ? that.canBreakPredicates != null && this.canBreakPredicates.equals(that.canBreakPredicates) : that.canBreakPredicates == null) // Paper +@@ -1988,9 +2025,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + hash = 61 * hash + (this.hasTool() ? this.tool.hashCode() : 0); + hash = 61 * hash + (this.hasJukeboxPlayable() ? this.jukebox.hashCode() : 0); + hash = 61 * hash + (this.hasEquippable() ? this.equippable.hashCode() : 0); +- hash = 61 * hash + (this.hasDamage() ? this.damage : 0); +- hash = 61 * hash + (this.hasMaxDamage() ? 1231 : 1237); +- hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); ++ hash = 61 * hash + (this.hasDamageValue() ? this.damage : -1); // Paper - preserve empty/0 damage ++ hash = 61 * hash + (this.hasMaxDamage() ? this.maxDamage.hashCode() : 0); // Paper - max damage is not a boolean ++ hash = 61 * hash + (this.attributeModifiers != null ? this.attributeModifiers.hashCode() : 0); // Paper - track only null attributes + hash = 61 * hash + (this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates.hashCode() : 0); // Paper + hash = 61 * hash + (this.canBreakPredicates != null ? this.canBreakPredicates.hashCode() : 0); // Paper + hash = 61 * hash + this.version; +@@ -2011,7 +2048,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + if (this.enchantments != null) { + clone.enchantments = new EnchantmentMap(this.enchantments); // Paper + } +- if (this.hasAttributeModifiers()) { ++ if (this.attributeModifiers != null) { // Paper + clone.attributeModifiers = LinkedHashMultimap.create(this.attributeModifiers); + } + if (this.customTag != null) { +@@ -2178,7 +2215,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + builder.put(CraftMetaItem.JUKEBOX_PLAYABLE.BUKKIT, this.jukebox); + } + +- if (this.hasDamage()) { ++ if (this.hasDamageValue()) { // Paper - preserve empty/0 damage + builder.put(CraftMetaItem.DAMAGE.BUKKIT, this.damage); + } + +@@ -2279,7 +2316,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + + static void serializeModifiers(Multimap modifiers, ImmutableMap.Builder builder, ItemMetaKey key) { +- if (modifiers == null || modifiers.isEmpty()) { ++ if (modifiers == null/* || modifiers.isEmpty()*/) { // Paper - null and an empty map have different behaviors + return; + } + +@@ -2361,7 +2398,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + // Paper start - improve checking handled tags + @org.jetbrains.annotations.VisibleForTesting + public static final Map, Set>> HANDLED_DCTS_PER_TYPE = new HashMap<>(); +- private static final Set> DEFAULT_HANDLED_DCTS = Set.of( ++ protected static final Set> DEFAULT_HANDLED_DCTS = Set.of( + CraftMetaItem.NAME.TYPE, + CraftMetaItem.ITEM_NAME.TYPE, + CraftMetaItem.LORE.TYPE, +@@ -2437,7 +2474,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + // Paper end - improve checking handled data component types + + protected static Optional getOrEmpty(DataComponentPatch tag, ItemMetaKeyType type) { +- Optional result = tag.get(type.TYPE); ++ // Paper start ++ return getOrEmpty(tag, type.TYPE); ++ } ++ protected static Optional getOrEmpty(final DataComponentPatch tag, final DataComponentType type) { ++ Optional result = tag.get(type); ++ // Paper end + + return (result != null) ? result : Optional.empty(); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +index e76749bffaf5a0bbd3a8d35f882edcc3598351b9..49889026661fb2a558e14569324016d637de27a0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +@@ -18,16 +18,30 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + + static final ItemMetaKeyType COLOR = new ItemMetaKeyType<>(DataComponents.DYED_COLOR, "color"); + +- private Color color = DEFAULT_LEATHER_COLOR; ++ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) + + CraftMetaLeatherArmor(CraftMetaItem meta) { + super(meta); +- CraftMetaLeatherArmor.readColor(this, meta); ++ // Paper start ++ if (!(meta instanceof CraftMetaLeatherArmor leatherMeta)) { ++ return; ++ } ++ ++ this.color = leatherMeta.color; ++ // Paper end + } + + CraftMetaLeatherArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper + super(tag, extraHandledDcts); // Paper +- CraftMetaLeatherArmor.readColor(this, tag); ++ // Paper start ++ getOrEmpty(tag, CraftMetaLeatherArmor.COLOR).ifPresent((dyedItemColor) -> { ++ if (!dyedItemColor.showInTooltip()) { ++ this.addItemFlags(ItemFlag.HIDE_DYE); ++ } ++ ++ this.color = dyedItemColor.rgb(); ++ }); ++ // Paper end + } + + CraftMetaLeatherArmor(Map map) { +@@ -38,7 +52,11 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + @Override + void applyToItem(CraftMetaItem.Applicator itemTag) { + super.applyToItem(itemTag); +- CraftMetaLeatherArmor.applyColor(this, itemTag); ++ // Paper start ++ if (this.hasColor()) { ++ itemTag.put(CraftMetaLeatherArmor.COLOR, new DyedItemColor(this.color, !this.hasItemFlag(ItemFlag.HIDE_DYE))); ++ } ++ // Paper end + } + + @Override +@@ -66,16 +84,16 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + + @Override + public Color getColor() { +- return this.color; ++ return this.color == null ? DEFAULT_LEATHER_COLOR : Color.fromRGB(this.color & 0xFFFFFF); // Paper + } + + @Override + public void setColor(Color color) { +- this.color = color == null ? DEFAULT_LEATHER_COLOR : color; ++ this.color = color == null ? null : color.asRGB(); // Paper + } + + boolean hasColor() { +- return CraftMetaLeatherArmor.hasColor(this); ++ return this.color != null; // Paper + } + + @Override +@@ -95,7 +113,7 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + if (meta instanceof CraftMetaLeatherArmor) { + CraftMetaLeatherArmor that = (CraftMetaLeatherArmor) meta; + +- return this.color.equals(that.color); ++ return this.hasColor() ? that.hasColor() && this.color.equals(that.color) : !that.hasColor(); // Paper - allow null + } + return true; + } +@@ -115,14 +133,16 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + return original != hash ? CraftMetaLeatherArmor.class.hashCode() ^ hash : hash; + } + ++ @io.papermc.paper.annotation.DoNotUse // Paper + static void readColor(LeatherArmorMeta meta, CraftMetaItem other) { + if (!(other instanceof CraftMetaLeatherArmor armorMeta)) { + return; + } + +- meta.setColor(armorMeta.color); ++ // meta.setColor(armorMeta.color); // Paper - commented out, color is now an integer and cannot be passed to setColor + } + ++ @io.papermc.paper.annotation.DoNotUse // Paper + static void readColor(LeatherArmorMeta meta, DataComponentPatch tag) { + getOrEmpty(tag, CraftMetaLeatherArmor.COLOR).ifPresent((dyedItemColor) -> { + if (!dyedItemColor.showInTooltip()) { +@@ -145,6 +165,7 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + return !DEFAULT_LEATHER_COLOR.equals(meta.getColor()); + } + ++ @io.papermc.paper.annotation.DoNotUse // Paper + static void applyColor(LeatherArmorMeta meta, CraftMetaItem.Applicator tag) { + if (CraftMetaLeatherArmor.hasColor(meta)) { + tag.put(CraftMetaLeatherArmor.COLOR, new DyedItemColor(meta.getColor().asRGB(), !meta.hasItemFlag(ItemFlag.HIDE_DYE))); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java +index 149356981e586e4f67d4543d3df94a2ea99333fc..06c72ed83dab9492b70bfd13f7f9c1a4cbef9e2f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java +@@ -29,7 +29,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { + + private Integer mapId; + private byte scaling = CraftMetaMap.SCALING_EMPTY; +- private Color color; ++ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) + + CraftMetaMap(CraftMetaItem meta) { + super(meta); +@@ -57,7 +57,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { + + getOrEmpty(tag, CraftMetaMap.MAP_COLOR).ifPresent((mapColor) -> { + try { +- this.color = Color.fromRGB(mapColor.rgb()); ++ this.color = mapColor.rgb(); // Paper + } catch (IllegalArgumentException ex) { + // Invalid colour + } +@@ -101,7 +101,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { + } + + if (this.hasColor()) { +- tag.put(CraftMetaMap.MAP_COLOR, new MapItemColor(this.color.asRGB())); ++ tag.put(CraftMetaMap.MAP_COLOR, new MapItemColor(this.color)); // Paper + } + } + +@@ -121,6 +121,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { + + @Override + public int getMapId() { ++ Preconditions.checkState(this.hasMapId(), "Item does not have map associated - check hasMapId() first!"); // Paper - fix NPE + return this.mapId; + } + +@@ -181,12 +182,12 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { + + @Override + public Color getColor() { +- return this.color; ++ return this.color == null ? null : Color.fromRGB(this.color & 0xFFFFFF); // Paper + } + + @Override + public void setColor(Color color) { +- this.color = color; ++ this.color = color == null ? null : color.asRGB(); // Paper + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java +index b118d8ecb505d187c02bb158f14df333f487a87f..fa1d1a7f37aadf2750f03a0e215fb25fa948f9aa 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java +@@ -70,6 +70,7 @@ public class CraftMetaOminousBottle extends CraftMetaItem implements OminousBott + + @Override + public int getAmplifier() { ++ Preconditions.checkState(this.hasAmplifier(), "'ominous_bottle_amplifier' data component is absent. Check hasAmplifier first!"); // Paper - fix NPE + return this.ominousBottleAmplifier; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +index 6f0eebcaffa20337cf5a7f8485f891c690d948ae..18dc2e83dab0821e5129bd68361de189363823b3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +@@ -38,7 +38,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + + private PotionType type; + private List customEffects; +- private Color color; ++ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) + private String customName; + + CraftMetaPotion(CraftMetaItem meta) { +@@ -63,7 +63,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + + potionContents.customColor().ifPresent((customColor) -> { + try { +- this.color = Color.fromRGB(customColor); ++ this.color = customColor; // Paper + } catch (IllegalArgumentException ex) { + // Invalid colour + } +@@ -132,7 +132,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + } + + Optional> defaultPotion = (this.hasBasePotionType()) ? Optional.of(CraftPotionType.bukkitToMinecraftHolder(this.type)) : Optional.empty(); +- Optional potionColor = (this.hasColor()) ? Optional.of(this.color.asRGB()) : Optional.empty(); ++ Optional potionColor = (this.hasColor()) ? Optional.of(this.color) : Optional.empty(); // Paper + Optional customName = Optional.ofNullable(this.customName); + + List effectList = new ArrayList<>(); +@@ -297,12 +297,12 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + + @Override + public Color getColor() { +- return this.color; ++ return this.color == null ? null : Color.fromRGB(this.color & 0xFFFFFF); // Paper + } + + @Override + public void setColor(Color color) { +- this.color = color; ++ this.color = color == null ? null : color.asRGB(); // Paper + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +index 967d8940aec0065bce496d5d7a8c73de5733bd2c..e229ca6acb6dbc3185f326f6653b3d66d835a9e5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +@@ -28,17 +28,29 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + + static final ItemMetaKeyType BASE_COLOR = new ItemMetaKeyType<>(DataComponents.BASE_COLOR, "Base", "base-color"); + +- private Banner banner; ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ private @org.jetbrains.annotations.Nullable List patterns; ++ private @org.jetbrains.annotations.Nullable DyeColor baseColor; ++ ++ // An empty pattern list is the same as the default on the Shield item, and will hence not be present in the data components of the stack. ++ private boolean hasPatterns() { ++ return this.patterns != null && !this.patterns.isEmpty(); ++ } ++ // Paper end - general item meta fixes - decoupled base colour and patterns + + CraftMetaShield(CraftMetaItem meta) { + super(meta); + + if (meta instanceof CraftMetaShield craftMetaShield) { +- if (craftMetaShield.banner != null) { +- this.banner = (Banner) craftMetaShield.banner.copy(); +- } ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ if (craftMetaShield.patterns != null) this.patterns = new ArrayList<>(craftMetaShield.getPatterns()); ++ if (craftMetaShield.baseColor != null) this.baseColor = craftMetaShield.baseColor; ++ // Paper end - general item meta fixes - decoupled base colour and patterns + } else if (meta instanceof CraftMetaBlockState state && state.hasBlockState() && state.getBlockState() instanceof Banner banner) { +- this.banner = (Banner) banner.copy(); ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ this.patterns = banner.getPatterns(); ++ this.baseColor = banner.getBaseColor(); ++ // Paper end - general item meta fixes - decoupled base colour and patterns + } + } + +@@ -46,7 +58,7 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + super(tag, extraHandledDcts); // Paper - improve checking handled tags in item meta + + getOrEmpty(tag, CraftMetaShield.BASE_COLOR).ifPresent((color) -> { +- this.banner = CraftMetaShield.getBlockState(DyeColor.getByWoolData((byte) color.getId())); ++ this.baseColor = DyeColor.getByWoolData((byte) color.getId()); // Paper - general item meta fixes - decoupled base colour and patterns + }); + + getOrEmpty(tag, CraftMetaBanner.PATTERNS).ifPresent((entityTag) -> { +@@ -68,7 +80,7 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + + String baseColor = SerializableMeta.getString(map, CraftMetaShield.BASE_COLOR.BUKKIT, true); + if (baseColor != null) { +- this.banner = CraftMetaShield.getBlockState(DyeColor.valueOf(baseColor)); ++ this.baseColor = DyeColor.valueOf(baseColor); // Paper - general item meta fixes - decoupled base colour and patterns + } + + Iterable rawPatternList = SerializableMeta.getObject(Iterable.class, map, CraftMetaBanner.PATTERNS.BUKKIT, true); +@@ -86,13 +98,14 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + void applyToItem(CraftMetaItem.Applicator tag) { + super.applyToItem(tag); + +- if (this.banner != null) { +- tag.put(CraftMetaShield.BASE_COLOR, net.minecraft.world.item.DyeColor.byId(this.banner.getBaseColor().getWoolData())); +- +- if (this.banner.numberOfPatterns() > 0) { ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ if (this.baseColor != null) tag.put(CraftMetaShield.BASE_COLOR, net.minecraft.world.item.DyeColor.byId(this.baseColor.getWoolData())); ++ if (this.patterns != null && !this.patterns.isEmpty()) { ++ { ++ // Paper end - general item meta fixes - decoupled base colour and patterns + List newPatterns = new ArrayList<>(); + +- for (Pattern p : this.banner.getPatterns()) { ++ for (Pattern p : this.patterns) { // Paper - general item meta fixes - decoupled base colour and patterns + newPatterns.add(new BannerPatternLayers.Layer(CraftPatternType.bukkitToMinecraftHolder(p.getPattern()), net.minecraft.world.item.DyeColor.byId(p.getColor().getWoolData()))); + } + +@@ -103,108 +116,84 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + + @Override + public List getPatterns() { +- if (this.banner == null) { ++ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns + return new ArrayList<>(); + } + +- return this.banner.getPatterns(); ++ return new ArrayList<>(this.patterns); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public void setPatterns(List patterns) { +- if (this.banner == null) { +- if (patterns.isEmpty()) { +- return; +- } +- +- this.banner = CraftMetaShield.getBlockState(null); +- } +- +- this.banner.setPatterns(patterns); ++ this.patterns = new ArrayList<>(patterns); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public void addPattern(Pattern pattern) { +- if (this.banner == null) { +- this.banner = CraftMetaShield.getBlockState(null); +- } +- +- this.banner.addPattern(pattern); ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ if (this.patterns == null) this.patterns = new ArrayList<>(); ++ this.patterns.add(pattern); ++ // Paper end - general item meta fixes - decoupled base colour and patterns + } + + @Override + public Pattern getPattern(int i) { +- if (this.banner == null) { ++ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns + throw new IndexOutOfBoundsException(i); + } + +- return this.banner.getPattern(i); ++ return this.patterns.get(i); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public Pattern removePattern(int i) { +- if (this.banner == null) { ++ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns + throw new IndexOutOfBoundsException(i); + } + +- return this.banner.removePattern(i); ++ return this.patterns.remove(i); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public void setPattern(int i, Pattern pattern) { +- if (this.banner == null) { ++ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns + throw new IndexOutOfBoundsException(i); + } + +- this.banner.setPattern(i, pattern); ++ this.patterns.set(i, pattern); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public int numberOfPatterns() { +- if (this.banner == null) { ++ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns + return 0; + } + +- return this.banner.numberOfPatterns(); ++ return this.patterns.size(); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public DyeColor getBaseColor() { +- if (this.banner == null) { +- return null; +- } +- +- return this.banner.getBaseColor(); ++ return this.baseColor; // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public void setBaseColor(DyeColor baseColor) { +- if (baseColor == null) { +- if (this.banner.numberOfPatterns() > 0) { +- this.banner.setBaseColor(DyeColor.WHITE); +- } else { +- this.banner = null; +- } +- } else { +- if (this.banner == null) { +- this.banner = CraftMetaShield.getBlockState(baseColor); +- } +- +- this.banner.setBaseColor(baseColor); +- } ++ this.baseColor = baseColor; // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { + super.serialize(builder); + +- if (this.banner != null) { +- builder.put(CraftMetaShield.BASE_COLOR.BUKKIT, this.banner.getBaseColor().toString()); +- +- if (this.banner.numberOfPatterns() > 0) { +- builder.put(CraftMetaBanner.PATTERNS.BUKKIT, this.banner.getPatterns()); +- } ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ if (this.baseColor != null) { ++ builder.put(CraftMetaShield.BASE_COLOR.BUKKIT, this.baseColor.toString()); ++ } ++ if (hasPatterns()) { ++ builder.put(CraftMetaBanner.PATTERNS.BUKKIT, this.patterns); + } ++ // Paper end - general item meta fixes - decoupled base colour and patterns + + return builder; + } +@@ -213,8 +202,13 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + int applyHash() { + final int original; + int hash = original = super.applyHash(); +- if (this.banner != null) { +- hash = 61 * hash + this.banner.hashCode(); ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ if (this.baseColor != null) { ++ hash = 61 * hash + this.baseColor.hashCode(); ++ } ++ if (hasPatterns()) { ++ hash = 61 * hash + this.patterns.hashCode(); ++ // Paper end - general item meta fixes - decoupled base colour and patterns + } + return original != hash ? CraftMetaShield.class.hashCode() ^ hash : hash; + } +@@ -225,29 +219,33 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + return false; + } + if (meta instanceof CraftMetaShield that) { +- return Objects.equal(this.banner, that.banner); ++ return Objects.equal(this.baseColor, that.baseColor) && Objects.equal(this.patterns, that.patterns); // Paper - general item meta fixes - decoupled base colour and patterns + } + return true; + } + + @Override + boolean notUncommon(CraftMetaItem meta) { +- return super.notUncommon(meta) && (meta instanceof CraftMetaShield || this.banner == null); ++ return super.notUncommon(meta) && (meta instanceof CraftMetaShield || (this.baseColor == null && !hasPatterns())); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + boolean isEmpty() { +- return super.isEmpty() && this.banner == null; ++ return super.isEmpty() && this.baseColor == null && !hasPatterns(); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public boolean hasBlockState() { +- return this.banner != null; ++ return this.baseColor != null || hasPatterns(); // Paper - general item meta fixes - decoupled base colour and patterns + } + + @Override + public BlockState getBlockState() { +- return (this.banner != null) ? this.banner.copy() : CraftMetaShield.getBlockState(null); ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ final Banner banner = CraftMetaShield.getBlockState(this.baseColor); ++ if (this.patterns != null) banner.setPatterns(this.patterns); ++ return banner; ++ // Paper end - general item meta fixes - decoupled base colour and patterns + } + + @Override +@@ -255,13 +253,18 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + Preconditions.checkArgument(blockState != null, "blockState must not be null"); + Preconditions.checkArgument(blockState instanceof Banner, "Invalid blockState"); + +- this.banner = (Banner) blockState; ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ final Banner banner = (Banner) blockState; ++ this.baseColor = banner.getBaseColor(); ++ this.patterns = banner.getPatterns(); ++ // Paper end - general item meta fixes - decoupled base colour and patterns + } + + // Paper start - add method to clear block state + @Override + public void clearBlockState() { +- this.banner = null; ++ this.baseColor = null; ++ this.patterns = null; + } + // Paper end - add method to clear block state + +@@ -275,9 +278,10 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + @Override + public CraftMetaShield clone() { + CraftMetaShield meta = (CraftMetaShield) super.clone(); +- if (this.banner != null) { +- meta.banner = (Banner) this.banner.copy(); +- } ++ // Paper start - general item meta fixes - decoupled base colour and patterns ++ meta.baseColor = this.baseColor; ++ meta.patterns = this.patterns == null ? null : new ArrayList<>(this.patterns); ++ // Paper start - general item meta fixes - decoupled base colour and patterns + return meta; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +index 302906467b12189e21633369c005736863f46dd5..5a4e5b8736ad2e2084e757e9d2034044e177d8f0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +@@ -112,10 +112,10 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { + // Fill in textures + PlayerProfile ownerProfile = new CraftPlayerProfile(this.profile); // getOwnerProfile may return null + if (ownerProfile.getTextures().isEmpty()) { +- ownerProfile.update().thenAccept((filledProfile) -> { ++ ownerProfile.update().thenAcceptAsync((filledProfile) -> { // Paper - run on main thread + this.setOwnerProfile(filledProfile); +- tag.put(CraftMetaSkull.SKULL_PROFILE, this.profile); +- }); ++ tag.skullCallback(this.profile); // Paper - actually set profile on itemstack ++ }, ((org.bukkit.craftbukkit.CraftServer) org.bukkit.Bukkit.getServer()).getServer()); // Paper - run on main thread + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +index 8ddf091b3ff1262b6c97e8fe72e0a80db5e1037d..be92ccda66f514459773916cc16b6c230e863444 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +@@ -121,6 +121,7 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { + + @Override + public EntitySnapshot getSpawnedEntity() { ++ if (this.entityTag == null) return null; // Paper - fix NPE + return CraftEntitySnapshot.create(this.entityTag); + } + +@@ -138,7 +139,7 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { + if (meta instanceof CraftMetaSpawnEgg) { + CraftMetaSpawnEgg that = (CraftMetaSpawnEgg) meta; + +- return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : this.entityTag == null; ++ return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : that.entityTag == null; // Paper + } + return true; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +index 17705059b81942e4df43a4a5180092e09c985ade..80e6b85a107d5236edba99540cb5074e2dc1485a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +@@ -120,6 +120,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB + + @Override + public DyeColor getPatternColor() { ++ com.google.common.base.Preconditions.checkState(this.hasVariant(), "This bucket doesn't have variant, check hasVariant first!"); // Paper - fix NPE + return CraftTropicalFish.getPatternColor(this.variant); + } + +@@ -133,6 +134,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB + + @Override + public DyeColor getBodyColor() { ++ com.google.common.base.Preconditions.checkState(this.hasVariant(), "This bucket doesn't have variant, check hasVariant first!"); // Paper - fix NPE + return CraftTropicalFish.getBodyColor(this.variant); + } + +@@ -146,6 +148,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB + + @Override + public TropicalFish.Pattern getPattern() { ++ com.google.common.base.Preconditions.checkState(this.hasVariant(), "This bucket doesn't have variant, check hasVariant first!"); // Paper - fix NPE + return CraftTropicalFish.getPattern(this.variant); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java +index e00b757d6059715e8697428008fcb3e6e7abbe2e..dcf02bd0f7f4c67f5ab98003cc932b960704eef1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java +@@ -136,4 +136,21 @@ public final class SerializableMeta implements ConfigurationSerializable { + } + throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz); + } ++ ++ // Paper start - General ItemMeta Fixes ++ public static java.util.Optional getObjectOptionally(Class clazz, Map map, Object field, boolean nullable) { ++ final Object object = map.get(field); ++ ++ if (clazz.isInstance(object)) { ++ return java.util.Optional.of(clazz.cast(object)); ++ } ++ if (object == null) { ++ if (!nullable) { ++ throw new NoSuchElementException(map + " does not contain " + field); ++ } ++ return java.util.Optional.empty(); ++ } ++ throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz); ++ } ++ // Paper end - General ItemMeta Fixes + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java +index 1f1589bcdb9e3abde7d25eac65326df1e7ed75ab..9b4c2502e45af4e7a58ff352f0f99c34d233f755 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java +@@ -170,7 +170,7 @@ public final class CraftEquippableComponent implements EquippableComponent { + + @Override + public void setAllowedEntities(Tag tag) { +- Preconditions.checkArgument(tag instanceof CraftEntityTag, "tag must be an entity tag"); ++ Preconditions.checkArgument(tag == null || tag instanceof CraftEntityTag, "tag must be an entity tag"); // Paper + + this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.model(), this.handle.cameraOverlay(), + (tag != null) ? Optional.of(((CraftEntityTag) tag).getHandle()) : Optional.empty(), +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java +index 9a4a1d903c22e9d2a0cbda95ceb8b1dcfb29112e..4f7914f96207feda67cd910213bb624df4802a06 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java +@@ -106,6 +106,7 @@ public final class CraftToolComponent implements ToolComponent { + public ToolRule addRule(Material block, Float speed, Boolean correctForDrops) { + Preconditions.checkArgument(block != null, "block must not be null"); + Preconditions.checkArgument(block.isBlock(), "block must be a block type, given %s", block.getKey()); ++ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed + + Holder.Reference nmsBlock = CraftBlockType.bukkitToMinecraft(block).builtInRegistryHolder(); + return this.addRule(HolderSet.direct(nmsBlock), speed, correctForDrops); +@@ -113,6 +114,7 @@ public final class CraftToolComponent implements ToolComponent { + + @Override + public ToolRule addRule(Collection blocks, Float speed, Boolean correctForDrops) { ++ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed + List> nmsBlocks = new ArrayList<>(blocks.size()); + + for (Material material : blocks) { +@@ -126,6 +128,7 @@ public final class CraftToolComponent implements ToolComponent { + @Override + public ToolRule addRule(Tag tag, Float speed, Boolean correctForDrops) { + Preconditions.checkArgument(tag instanceof CraftBlockTag, "tag must be a block tag"); ++ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed + return this.addRule(((CraftBlockTag) tag).getHandle(), speed, correctForDrops); + } + +@@ -258,6 +261,7 @@ public final class CraftToolComponent implements ToolComponent { + + @Override + public void setSpeed(Float speed) { ++ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed + this.handle = new Tool.Rule(this.handle.blocks(), Optional.ofNullable(speed), this.handle.correctForDrops()); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java +index 952e7fa022161d1d21ba1a4f43abe5ee221dee4b..0f86ff23cc6a2f617fc5ef67e576e1e3cb29034c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java +@@ -55,7 +55,7 @@ public final class CraftUseCooldownComponent implements UseCooldownComponent { + + @Override + public void setCooldownSeconds(float eatSeconds) { +- Preconditions.checkArgument(eatSeconds >= 0, "eatSeconds cannot be less than 0"); ++ Preconditions.checkArgument(eatSeconds > 0, "eatSeconds must be positive"); // Paper + + this.handle = new UseCooldown(eatSeconds, this.handle.cooldownGroup()); + } +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java +index 9cc1ef5c9221dd7d2069b280f0c91ce9439a995a..1c80fe7549d70ae16c7b755c22752549261f072a 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java +@@ -94,7 +94,7 @@ public class DeprecatedItemMetaCustomValueTest { + public void testNBTTagStoring() { + CraftMetaItem itemMeta = this.createComplexItemMeta(); + +- CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); ++ CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator() {}; // Paper + itemMeta.applyToItem(compound); + + assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java +index 130c4500a5e854480962c8f720b1df4c67d43c33..f33b49915d1f1f0838c49ac943e8d4d619450f6b 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java +@@ -128,7 +128,7 @@ public class PersistentDataContainerTest { + public void testNBTTagStoring() { + CraftMetaItem itemMeta = this.createComplexItemMeta(); + +- CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); ++ CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator() {}; // Paper + itemMeta.applyToItem(compound); + + assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper +@@ -474,7 +474,7 @@ public class PersistentDataContainerTest { + assertEquals(List.of(), container.get(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings())); + + // Write and read the entire container to NBT +- final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator(); ++ final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator() {}; // Paper + craftItem.applyToItem(storage); + + final CraftMetaItem readItem = new CraftMetaItem(storage.build(), null); // Paper diff --git a/patches/server/0954-General-ItemMeta-fixes.patch b/patches/server/0954-General-ItemMeta-fixes.patch deleted file mode 100644 index ce6a04d22f..0000000000 --- a/patches/server/0954-General-ItemMeta-fixes.patch +++ /dev/null @@ -1,2152 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 27 Apr 2024 20:56:17 -0700 -Subject: [PATCH] General ItemMeta fixes - -== AT == -private-f net/minecraft/world/item/ItemStack components -public net/minecraft/world/food/FoodProperties DEFAULT_EAT_SECONDS -public org/bukkit/craftbukkit/block/CraftBlockStates getBlockState(Lorg/bukkit/World;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/entity/BlockEntity;)Lorg/bukkit/craftbukkit/block/CraftBlockState; -public net/minecraft/world/level/block/entity/BlockEntity saveId(Lnet/minecraft/nbt/CompoundTag;)V - -Co-authored-by: GhastCraftHD - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 98b5208baeaa12a5ff2788e457c542000d6ea48b..babd89f39c43b0c64709d99bf8aca6cdc6ca1b24 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -1361,6 +1361,11 @@ public final class ItemStack implements DataComponentHolder { - public void setItem(Item item) { - this.bukkitStack = null; // Paper - this.item = item; -+ // Paper start - change base component prototype -+ final DataComponentPatch patch = this.getComponentsPatch(); -+ this.components = new PatchedDataComponentMap(this.item.components()); -+ this.applyComponents(patch); -+ // Paper end - change base component prototype - } - // CraftBukkit end - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 63e234fb72952dcede4eeaa5d3d3390d137d88a2..b4aff394694417cff1930cf8fbd6696b9f9c9d01 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -152,6 +152,11 @@ public abstract class BlockEntity { - CompoundTag nbttagcompound = new CompoundTag(); - - this.saveAdditional(nbttagcompound, registries); -+ // Paper start - store PDC here as well -+ if (this.persistentDataContainer != null && !this.persistentDataContainer.isEmpty()) { -+ nbttagcompound.put("PublicBukkitValues", this.persistentDataContainer.toTagCompound()); -+ } -+ // Paper end - return nbttagcompound; - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -index fe7e3e0628783d8d1be9635b689da8a9cb46c5d7..04ae258a2f8e98421340d29d5cceedec045171b7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -@@ -151,6 +151,19 @@ public abstract class CraftBlockEntityState extends Craft - return this.snapshot.getUpdateTag(this.getRegistryAccess()); - } - -+ // Paper start - properly save blockentity itemstacks -+ public CompoundTag getSnapshotCustomNbtOnly() { -+ this.applyTo(this.snapshot); -+ final CompoundTag nbt = this.snapshot.saveCustomOnly(this.getRegistryAccess()); -+ this.snapshot.removeComponentsFromTag(nbt); -+ if (!nbt.isEmpty()) { -+ // have to include the "id" if it's going to have block entity data -+ this.snapshot.saveId(nbt); -+ } -+ return nbt; -+ } -+ // Paper end -+ - // copies the data of the given tile entity to this block state - protected void load(T tileEntity) { - if (tileEntity != null && tileEntity != this.snapshot) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index dfdabf86433d323966a748baef769cf0462d3f38..bb2b4528692aed8e3341428697a60c0abee13779 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -291,7 +291,9 @@ public final class CraftItemStack extends ItemStack { - - @Override - public void removeEnchantments() { -- this.handle.remove(DataComponents.ENCHANTMENTS); -+ if (this.handle != null) { // Paper - fix NPE -+ this.handle.set(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); // Paper - set to default instead of removing the component -+ } // Paper - } - - @Override -@@ -353,7 +355,14 @@ public final class CraftItemStack extends ItemStack { - // Paper end - improve handled tags on type change - // Paper start - public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { -- final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); -+ // Paper start - support updating profile after resolving it -+ final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() { -+ @Override -+ void skullCallback(final net.minecraft.world.item.component.ResolvableProfile profile) { -+ itemStack.set(DataComponents.PROFILE, profile); -+ } -+ }; -+ // Paper end - support updating profile after resolving it - ((CraftMetaItem) itemMeta).applyToItem(tag); - itemStack.applyComponents(tag.build()); - } -@@ -401,15 +410,20 @@ public final class CraftItemStack extends ItemStack { - if (itemMeta == null) return true; - - if (!((CraftMetaItem) itemMeta).isEmpty()) { -- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); -+ // Paper start - support updating profile after resolving it -+ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() { -+ @Override -+ void skullCallback(final net.minecraft.world.item.component.ResolvableProfile resolvableProfile) { -+ item.set(DataComponents.PROFILE, resolvableProfile); -+ } -+ }; -+ // Paper end - support updating profile after resolving it - - ((CraftMetaItem) itemMeta).applyToItem(tag); -- item.restorePatch(tag.build()); -- } -- // SpigotCraft#463 this is required now by the Vanilla client, so mimic ItemStack constructor in ensuring it -- if (item.getItem() != null && item.getMaxDamage() > 0) { -- item.setDamageValue(item.getDamageValue()); -+ item.restorePatch(DataComponentPatch.EMPTY); // Paper - properly apply the new patch from itemmeta -+ item.applyComponents(tag.build()); // Paper - properly apply the new patch from itemmeta - } -+ // Paper - this is no longer needed - - return true; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -index 169fefb64e1af444f7c2efb1234cb6e7779fb717..cb49ff5c94f33f00f626a31d958d2025819d1da8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -@@ -118,14 +118,13 @@ public class CraftMetaAxolotlBucket extends CraftMetaItem implements AxolotlBuck - - @Override - public Axolotl.Variant getVariant() { -+ com.google.common.base.Preconditions.checkState(this.hasVariant(), "Variant is absent, check hasVariant first!"); // Paper - fix NPE - return Axolotl.Variant.values()[this.variant]; - } - - @Override - public void setVariant(Axolotl.Variant variant) { -- if (variant == null) { -- variant = Axolotl.Variant.LUCY; -- } -+ com.google.common.base.Preconditions.checkArgument(variant != null, "Variant cannot be null!"); // Paper - this.variant = variant.ordinal(); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -index d0a8cd89da3b8d87248494056470c306f8fb5ae8..fdc0c1d73bb523f003e4169589f1002375b9c88c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -@@ -69,6 +69,7 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { - void applyToItem(CraftMetaItem.Applicator tag) { - super.applyToItem(tag); - -+ if (this.patterns.isEmpty()) return; // Paper - don't write empty patterns - List newPatterns = new ArrayList<>(); - - for (Pattern p : this.patterns) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -index 413e41f113226b8a2e9b30bb519076d78e451fa0..d688339a57f0b4f12588ced0f7860a0d77eae728 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -@@ -52,10 +52,24 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - - @ItemMetaKey.Specific(ItemMetaKey.Specific.To.NBT) - static final ItemMetaKeyType BLOCK_ENTITY_TAG = new ItemMetaKeyType<>(DataComponents.BLOCK_ENTITY_DATA, "BlockEntityTag"); -+ static final ItemMetaKey BLOCK_ENTITY_TAG_CUSTOM_DATA = new ItemMetaKey("block-entity-tag"); // Paper -+ static final ItemMetaKey BLOCK_ENTITY_COMPONENTS = new ItemMetaKey("block-entity-components"); // Paper - - final Material material; -- private CraftBlockEntityState blockEntityTag; -- private BlockVector position; -+ // Paper start - store data separately -+ DataComponentMap components; -+ CustomData blockEntityTag; -+ { -+ // this is because the fields are possibly assigned in the super constructor (via deserializeInternal) -+ // and a direct field initialization happens **after** the super constructor. So we only want to -+ // set them to empty if they weren't assigned by the super constructor (via deserializeInternal) -+ this.components = this.components != null ? this.components : DataComponentMap.EMPTY; -+ this.blockEntityTag = this.blockEntityTag != null ? this.blockEntityTag : CustomData.EMPTY; -+ } -+ private Material materialForBlockEntityType() { -+ return this.material; -+ } -+ // Paper end - private CompoundTag internalTag; - - CraftMetaBlockState(CraftMetaItem meta, Material material) { -@@ -64,47 +78,61 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - - if (!(meta instanceof CraftMetaBlockState) - || ((CraftMetaBlockState) meta).material != material) { -- this.blockEntityTag = null; -+ // Paper start -+ this.components = DataComponentMap.EMPTY; -+ this.blockEntityTag = CustomData.EMPTY; -+ // Paper end - return; - } - - CraftMetaBlockState te = (CraftMetaBlockState) meta; -+ // Paper start -+ this.components = te.components; - this.blockEntityTag = te.blockEntityTag; -- this.position = te.position; -+ // Paper end - } - - CraftMetaBlockState(DataComponentPatch tag, Material material, final Set> extraHandledDcts) { // Paper - super(tag, extraHandledDcts); // Paper - this.material = material; - -- getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((blockTag) -> { -- CompoundTag nbt = blockTag.copyTag(); -+ // Paper start - move to separate method to be re-called -+ this.updateBlockState(tag); -+ } - -- this.blockEntityTag = CraftMetaBlockState.getBlockState(material, nbt); -- if (nbt.contains("x", CraftMagicNumbers.NBT.TAG_ANY_NUMBER) && nbt.contains("y", CraftMagicNumbers.NBT.TAG_ANY_NUMBER) && nbt.contains("z", CraftMagicNumbers.NBT.TAG_ANY_NUMBER)) { -- this.position = new BlockVector(nbt.getInt("x"), nbt.getInt("y"), nbt.getInt("z")); -- } -+ private void updateBlockState(final DataComponentPatch tag) { -+ // Paper end -+ getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((nbt) -> { -+ this.blockEntityTag = nbt; // Paper - }); - - if (!tag.isEmpty()) { -- CraftBlockEntityState blockEntityTag = this.blockEntityTag; -- if (blockEntityTag == null) { -- blockEntityTag = CraftMetaBlockState.getBlockState(material, null); -- } -- -- // Convert to map -- PatchedDataComponentMap map = new PatchedDataComponentMap(DataComponentMap.EMPTY); -- map.applyPatch(tag); -- // Apply -- Set> applied = blockEntityTag.applyComponents(map, tag); -+ // Paper start - store data in a DataComponentMap to be used to construct CraftBlockEntityStates -+ final DataComponentMap.Builder map = DataComponentMap.builder(); -+ final net.minecraft.world.level.block.entity.BlockEntity dummyBlockEntity = java.util.Objects.requireNonNull( -+ org.bukkit.craftbukkit.block.CraftBlockStates.createNewTileEntity(this.materialForBlockEntityType()) -+ ); -+ -+ // we don't care about what's in here, all -+ // we want is to know which data component types are referenced -+ Set> applied = dummyBlockEntity.applyComponentsSet(DataComponentMap.EMPTY, DataComponentPatch.EMPTY); -+ // Paper end - store data in a DataComponentMap to be used to construct CraftBlockEntityStates - // Mark applied components as handled - for (DataComponentType seen : applied) { - this.unhandledTags.clear(seen); - } - // Only set blockEntityTag if something was applied - if (!applied.isEmpty()) { -- this.blockEntityTag = blockEntityTag; -+ // Paper start -+ for (final DataComponentType type : applied) { -+ if (CraftMetaItem.DEFAULT_HANDLED_DCTS.contains(type)) continue; -+ getOrEmpty(tag, type).ifPresent(value -> { -+ map.set(type, value); -+ }); -+ } -+ // Paper end - } -+ this.components = map.build(); // Paper - } - } - -@@ -118,42 +146,43 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - this.material = Material.AIR; - } - if (this.internalTag != null) { -- this.blockEntityTag = CraftMetaBlockState.getBlockState(this.material, this.internalTag); -+ this.setBlockState(CraftMetaBlockState.getBlockState(this.material, this.internalTag)); // Paper - general item meta fixes - pass through setter - this.internalTag = null; - } -- this.position = SerializableMeta.getObject(BlockVector.class, map, "blockPosition", true); -+ // Paper start - general item meta fixes - parse spigot legacy position and merge into block entity tag -+ final BlockVector legacyPosition = SerializableMeta.getObject(BlockVector.class, map, "blockPosition", true); -+ if (legacyPosition != null) { -+ this.blockEntityTag = this.blockEntityTag.update(t -> { -+ if (t.isEmpty()) { -+ BlockEntity.addEntityType(t, java.util.Objects.requireNonNull(CraftBlockStates.getBlockEntityType(this.materialForBlockEntityType()))); -+ } -+ t.putInt("x", legacyPosition.getBlockX()); -+ t.putInt("y", legacyPosition.getBlockY()); -+ t.putInt("z", legacyPosition.getBlockZ()); -+ }); -+ } -+ // Paper end - general item meta fixes - parse spigot legacy position and merge into block entity tag - } - - @Override - void applyToItem(CraftMetaItem.Applicator tag) { - super.applyToItem(tag); - -- CompoundTag nbt = null; -- if (this.blockEntityTag != null) { -- nbt = this.blockEntityTag.getItemNBT(); -- -- for (TypedDataComponent component : this.blockEntityTag.collectComponents()) { -- tag.putIfAbsent(component); -- } -+ // Paper start - accurately replicate logic for creating ItemStack from BlockEntity -+ // taken from BlockEntity#saveToItem and BlockItem#setBlockEntityData -+ final CompoundTag nbt = this.blockEntityTag.copyTag(); -+ if (nbt.contains("id", CraftMagicNumbers.NBT.TAG_STRING)) { -+ tag.put(CraftMetaBlockState.BLOCK_ENTITY_TAG, CustomData.of(nbt)); -+ } else if (!nbt.isEmpty()) { -+ BlockEntity.addEntityType(nbt, java.util.Objects.requireNonNull(CraftBlockStates.getBlockEntityType(this.materialForBlockEntityType()))); -+ tag.put(CraftMetaBlockState.BLOCK_ENTITY_TAG, CustomData.of(nbt)); - } - -- if (this.position != null) { -- if (nbt == null) { -- nbt = new CompoundTag(); -- } -- -- nbt.putInt("x", this.position.getBlockX()); -- nbt.putInt("y", this.position.getBlockY()); -- nbt.putInt("z", this.position.getBlockZ()); -- } -- -- if (nbt != null && !nbt.isEmpty()) { -- CraftBlockEntityState tile = (this.blockEntityTag != null) ? this.blockEntityTag : CraftMetaBlockState.getBlockState(this.material, null); -- // See ItemBlock#setBlockEntityData -- tile.addEntityType(nbt); -- -- tag.put(CraftMetaBlockState.BLOCK_ENTITY_TAG, CustomData.of(nbt)); -+ for (final TypedDataComponent component : this.components) { -+ if (CraftMetaItem.DEFAULT_HANDLED_DCTS.contains(component.type())) continue; // if the component type was already handled by CraftMetaItem, don't add it again -+ tag.builder.set(component); - } -+ // Paper end - } - - @Override -@@ -162,23 +191,35 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - - if (tag.contains(CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { - this.internalTag = tag.getCompound(CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT); -+ return; // Paper - if legacy, don't check anything else -+ } -+ // Paper start - new serialization format -+ if (tag.contains(CraftMetaBlockState.BLOCK_ENTITY_TAG_CUSTOM_DATA.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { -+ this.blockEntityTag = CustomData.of(tag.getCompound(CraftMetaBlockState.BLOCK_ENTITY_TAG_CUSTOM_DATA.NBT)); -+ } -+ if (tag.contains(CraftMetaBlockState.BLOCK_ENTITY_COMPONENTS.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { -+ this.components = DataComponentMap.CODEC.parse(org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE), tag.getCompound(CraftMetaBlockState.BLOCK_ENTITY_COMPONENTS.NBT)).getOrThrow(); - } -+ // Paper end - new serialization format - } - - @Override - void serializeInternal(final Map internalTags) { -- if (this.blockEntityTag != null) { -- internalTags.put(CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT, this.blockEntityTag.getSnapshotNBT()); -+ // Paper start - new serialization format -+ if (!this.blockEntityTag.isEmpty()) { -+ internalTags.put(CraftMetaBlockState.BLOCK_ENTITY_TAG_CUSTOM_DATA.NBT, this.blockEntityTag.getUnsafe()); // unsafe because it's serialized right away - } -+ if (!this.components.isEmpty()) { -+ final Tag componentsTag = DataComponentMap.CODEC.encodeStart(org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE), this.components).getOrThrow(); -+ internalTags.put(CraftMetaBlockState.BLOCK_ENTITY_COMPONENTS.NBT, componentsTag); -+ } -+ // Paper end - new serialization format - } - - @Override - ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { - super.serialize(builder); - builder.put("blockMaterial", this.material.name()); -- if (this.position != null) { -- builder.put("blockPosition", this.position); -- } - return builder; - } - -@@ -186,12 +227,10 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - int applyHash() { - final int original; - int hash = original = super.applyHash(); -- if (this.blockEntityTag != null) { -- hash = 61 * hash + this.blockEntityTag.hashCode(); -- } -- if (this.position != null) { -- hash = 61 * hash + this.position.hashCode(); -- } -+ // Paper start -+ hash = 61 * hash + this.blockEntityTag.hashCode(); -+ hash = 61 * hash + this.components.hashCode(); -+ // Paper end - return original != hash ? CraftMetaBlockState.class.hashCode() ^ hash : hash; - } - -@@ -203,52 +242,75 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - if (meta instanceof CraftMetaBlockState) { - CraftMetaBlockState that = (CraftMetaBlockState) meta; - -- return Objects.equal(this.blockEntityTag, that.blockEntityTag) && Objects.equal(this.position, that.position); -+ return Objects.equal(this.blockEntityTag, that.blockEntityTag) && Objects.equal(this.components, that.components); // Paper - } - return true; - } - - boolean isBlockStateEmpty() { -- return !(this.blockEntityTag != null || this.position != null); -+ return !(this.blockEntityTag != null); - } - - @Override - boolean notUncommon(CraftMetaItem meta) { -- return super.notUncommon(meta) && (meta instanceof CraftMetaBlockState || this.isBlockStateEmpty()); -+ return super.notUncommon(meta) && (meta instanceof CraftMetaBlockState || (this.blockEntityTag.isEmpty() && this.components.isEmpty())); // Paper - } - - @Override - boolean isEmpty() { -- return super.isEmpty() && this.isBlockStateEmpty(); -+ return super.isEmpty() && this.blockEntityTag.isEmpty() && this.components.isEmpty(); // Paper - } - - @Override - public CraftMetaBlockState clone() { - CraftMetaBlockState meta = (CraftMetaBlockState) super.clone(); -- if (this.blockEntityTag != null) { -- meta.blockEntityTag = this.blockEntityTag.copy(); -- } -- if (this.position != null) { -- meta.position = this.position.clone(); -- } -+ // Paper start - no need for "clone" because they are essentially immutables -+ meta.blockEntityTag = this.blockEntityTag; -+ meta.components = this.components; -+ // Paper end - return meta; - } - - @Override - public boolean hasBlockState() { -- return this.blockEntityTag != null; -+ return !this.blockEntityTag.isEmpty() || !this.components.isEmpty(); // Paper - } - - // Paper start - add method to clear block state - @Override - public void clearBlockState() { -- this.blockEntityTag = null; -+ // Paper start -+ this.blockEntityTag = CustomData.EMPTY; -+ this.components = DataComponentMap.EMPTY; -+ // Paper end - } - // Paper end - add method to clear block state - - @Override -- public BlockState getBlockState() { -- return (this.blockEntityTag != null) ? this.blockEntityTag.copy() : CraftMetaBlockState.getBlockState(this.material, null); -+ // Paper start - create blockstate on-demand -+ public CraftBlockEntityState getBlockState() { -+ BlockPos pos = BlockPos.ZERO; -+ final Material stateMaterial = this.materialForBlockEntityType(); -+ if (!this.blockEntityTag.isEmpty()) { -+ // Paper "id" field is always present now -+ pos = BlockEntity.getPosFromTag(this.blockEntityTag.getUnsafe()); // unsafe is fine here, just querying -+ } -+ final net.minecraft.world.level.block.entity.BlockEntityType type = java.util.Objects.requireNonNull(CraftBlockStates.getBlockEntityType(stateMaterial)); -+ final net.minecraft.world.level.block.state.BlockState nmsBlockState = ((org.bukkit.craftbukkit.block.data.CraftBlockData) this.getBlockData(stateMaterial)).getState(); -+ final net.minecraft.world.level.block.entity.BlockEntity blockEntity = java.util.Objects.requireNonNull(type.create(pos, nmsBlockState)); -+ if (!this.blockEntityTag.isEmpty()) { -+ this.blockEntityTag.loadInto(blockEntity, org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry()); -+ } -+ final PatchedDataComponentMap patchedMap = new PatchedDataComponentMap(nmsBlockState.getBlock().asItem().components()); -+ patchedMap.setAll(this.components); -+ final Applicator applicator = new Applicator() {}; -+ super.applyToItem(applicator); -+ patchedMap.applyPatch(applicator.build()); -+ blockEntity.applyComponents(nmsBlockState.getBlock().asItem().components(), patchedMap.asPatch()); -+ -+ // This is expected to always return a CraftBlockEntityState for the passed material: -+ return (CraftBlockEntityState) CraftBlockStates.getBlockState(null, pos, nmsBlockState, blockEntity); -+ // Paper end - } - - private static CraftBlockEntityState getBlockState(Material material, CompoundTag blockEntityTag) { -@@ -278,7 +340,23 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - Class blockStateType = CraftBlockStates.getBlockStateType(stateMaterial); - Preconditions.checkArgument(blockStateType == blockState.getClass() && blockState instanceof CraftBlockEntityState, "Invalid blockState for %s", this.material); - -- this.blockEntityTag = (CraftBlockEntityState) blockState; -+ // Paper start - when a new BlockState is set, the components from that block entity -+ // have to be used to update the fields on CraftMetaItem -+ final CraftBlockEntityState craftBlockState = (CraftBlockEntityState) blockState; -+ final CompoundTag data = craftBlockState.getSnapshotCustomNbtOnly(); -+ final PatchedDataComponentMap patchedMap = new net.minecraft.core.component.PatchedDataComponentMap(craftBlockState.getHandle().getBlock().asItem().components()); -+ final net.minecraft.core.component.DataComponentMap map = craftBlockState.collectComponents(); -+ patchedMap.setAll(map); -+ if (!data.isEmpty()) { -+ patchedMap.set(BLOCK_ENTITY_TAG.TYPE, CustomData.of(data)); -+ } -+ final DataComponentPatch patch = patchedMap.asPatch(); -+ this.updateFromPatch(patch, null); -+ // we have to reset the fields because this should be like a "new" block entity is being used -+ this.blockEntityTag = CustomData.EMPTY; -+ this.components = DataComponentMap.EMPTY; -+ this.updateBlockState(patch); -+ // Paper end - } - - private static Material shieldToBannerHack(CompoundTag tag) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -index 257c835bc280eee9ee73ae75b5249bb568a687d0..70f20de37c1f8d57a8d9fe00dcd864fdd9948ec2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -@@ -34,7 +34,7 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta, WritableBo - @ItemMetaKey.Specific(ItemMetaKey.Specific.To.NBT) - static final ItemMetaKeyType BOOK_CONTENT = new ItemMetaKeyType<>(DataComponents.WRITABLE_BOOK_CONTENT); - static final ItemMetaKey BOOK_PAGES = new ItemMetaKey("pages"); -- static final int MAX_PAGES = Integer.MAX_VALUE; // SPIGOT-6911: Use Minecraft limits -+ static final int MAX_PAGES = WritableBookContent.MAX_PAGES; // SPIGOT-6911: Use Minecraft limits // Paper - static final int MAX_PAGE_LENGTH = WritableBookContent.PAGE_EDIT_LENGTH; // SPIGOT-6911: Use Minecraft limits - - // We store the pages in their raw original text representation. See SPIGOT-5063, SPIGOT-5350, SPIGOT-3206 -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -index cbb3d80cc7cd81b2505dff999a0baede737165f7..040dac82e484cb44b3afd444b4bbd1fd994bfe7c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -@@ -124,13 +124,13 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta { - void applyToItem(CraftMetaItem.Applicator itemData) { - super.applyToItem(itemData); - -+ List> list = new ArrayList<>(); // Paper - General ItemMeta Fixes - if (this.pages != null) { -- List> list = new ArrayList<>(); - for (Component page : this.pages) { - list.add(Filterable.passThrough(page)); - } -- itemData.put(CraftMetaBookSigned.BOOK_CONTENT, new WrittenBookContent(Filterable.from(FilteredText.passThrough(this.title)), this.author, this.generation, list, this.resolved)); - } -+ itemData.put(CraftMetaBookSigned.BOOK_CONTENT, new WrittenBookContent(Filterable.from(this.title == null ? FilteredText.EMPTY : FilteredText.passThrough(this.title)), this.author == null ? "" : this.author, this.generation, list, this.resolved)); // Paper - General ItemMeta Fixes - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -index 2736a87a6c481da0575e6e29ea08faa539c24378..51da0db4da3549efd69f367e28450408968fa8d0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -@@ -41,7 +41,7 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { - bundle.items().forEach((item) -> { - ItemStack itemStack = CraftItemStack.asCraftMirror(item); - -- if (!itemStack.getType().isAir()) { // SPIGOT-7174 - Avoid adding air -+ if (!itemStack.isEmpty()) { // SPIGOT-7174 - Avoid adding air // Paper - this.addItem(itemStack); - } - }); -@@ -54,7 +54,7 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { - Iterable items = SerializableMeta.getObject(Iterable.class, map, CraftMetaBundle.ITEMS.BUKKIT, true); - if (items != null) { - for (Object stack : items) { -- if (stack instanceof ItemStack itemStack && !itemStack.getType().isAir()) { // SPIGOT-7174 - Avoid adding air -+ if (stack instanceof ItemStack itemStack && !itemStack.isEmpty()) { // SPIGOT-7174 - Avoid adding air // Paper - this.addItem(itemStack); - } - } -@@ -110,7 +110,7 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { - - @Override - public void addItem(ItemStack item) { -- Preconditions.checkArgument(item != null && !item.getType().isAir(), "item is null or air"); -+ Preconditions.checkArgument(item != null && !item.isEmpty(), "item is null or empty"); // Paper - - if (this.items == null) { - this.items = new ArrayList<>(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -index dc6398cfbd6e749733c3a681e1eb8ce15c3b2c5e..51d7263cdd34359d9cdf72cc01ba654b519f838d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -@@ -11,16 +11,30 @@ import org.bukkit.inventory.meta.ColorableArmorMeta; - @DelegateDeserialization(SerializableMeta.class) - public class CraftMetaColorableArmor extends CraftMetaArmor implements ColorableArmorMeta { - -- private Color color = DEFAULT_LEATHER_COLOR; -+ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) - - CraftMetaColorableArmor(CraftMetaItem meta) { - super(meta); -- CraftMetaLeatherArmor.readColor(this, meta); -+ // Paper start -+ if (!(meta instanceof CraftMetaColorableArmor armorMeta)) { -+ return; -+ } -+ -+ this.color = armorMeta.color; -+ // Paper end - } - - CraftMetaColorableArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper - super(tag, extraHandledDcts); // Paper -- CraftMetaLeatherArmor.readColor(this, tag); -+ // Paper start -+ getOrEmpty(tag, CraftMetaLeatherArmor.COLOR).ifPresent((dyedItemColor) -> { -+ if (!dyedItemColor.showInTooltip()) { -+ this.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_DYE); -+ } -+ -+ this.color = dyedItemColor.rgb(); -+ }); -+ // Paper end - } - - CraftMetaColorableArmor(Map map) { -@@ -31,7 +45,11 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable - @Override - void applyToItem(CraftMetaItem.Applicator itemTag) { - super.applyToItem(itemTag); -- CraftMetaLeatherArmor.applyColor(this, itemTag); -+ // Paper start -+ if (this.hasColor()) { -+ itemTag.put(CraftMetaLeatherArmor.COLOR, new net.minecraft.world.item.component.DyedItemColor(this.color, !this.hasItemFlag(org.bukkit.inventory.ItemFlag.HIDE_DYE))); -+ } -+ // Paper end - } - - @Override -@@ -52,16 +70,16 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable - - @Override - public Color getColor() { -- return this.color; -+ return this.color == null ? DEFAULT_LEATHER_COLOR : Color.fromRGB(this.color & 0xFFFFFF); // Paper - this should really be nullable - } - - @Override - public void setColor(Color color) { -- this.color = color == null ? DEFAULT_LEATHER_COLOR : color; -+ this.color = color == null ? null : color.asRGB(); // Paper - } - - boolean hasColor() { -- return CraftMetaLeatherArmor.hasColor(this); -+ return this.color != null; // Paper - } - - @Override -@@ -81,7 +99,7 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable - if (meta instanceof CraftMetaColorableArmor) { - CraftMetaColorableArmor that = (CraftMetaColorableArmor) meta; - -- return this.color.equals(that.color); -+ return this.hasColor() ? that.hasColor() && this.color.equals(that.color) : !that.hasColor(); // Paper - allow null - } - return true; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -index 69a112b3a9726966aecbe687d905fd1a11cfa1e3..ab424926c282fb03eabd1eebd2b7980899ef28e3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -@@ -31,11 +31,7 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - static final ItemMetaKey LODESTONE_POS_Z = new ItemMetaKey("LodestonePosZ"); - static final ItemMetaKey LODESTONE_TRACKED = new ItemMetaKey("LodestoneTracked"); - -- private ResourceKey lodestoneWorld; -- private int lodestoneX; -- private int lodestoneY; -- private int lodestoneZ; -- private boolean tracked = true; -+ private LodestoneTracker tracker; // Paper - use LodestoneTracker type - - CraftMetaCompass(CraftMetaItem meta) { - super(meta); -@@ -43,24 +39,13 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - return; - } - CraftMetaCompass compassMeta = (CraftMetaCompass) meta; -- this.lodestoneWorld = compassMeta.lodestoneWorld; -- this.lodestoneX = compassMeta.lodestoneX; -- this.lodestoneY = compassMeta.lodestoneY; -- this.lodestoneZ = compassMeta.lodestoneZ; -- this.tracked = compassMeta.tracked; -+ this.tracker = compassMeta.tracker; // Paper - use LodestoneTracker type - } - - CraftMetaCompass(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper - super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaCompass.LODESTONE_TARGET).ifPresent((lodestoneTarget) -> { -- lodestoneTarget.target().ifPresent((target) -> { -- this.lodestoneWorld = target.dimension(); -- BlockPos pos = target.pos(); -- this.lodestoneX = pos.getX(); -- this.lodestoneY = pos.getY(); -- this.lodestoneZ = pos.getZ(); -- }); -- this.tracked = lodestoneTarget.tracked(); -+ this.tracker = lodestoneTarget; // Paper - use LodestoneTracker type - }); - } - -@@ -68,10 +53,13 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - super(map); - String lodestoneWorldString = SerializableMeta.getString(map, CraftMetaCompass.LODESTONE_POS_WORLD.BUKKIT, true); - if (lodestoneWorldString != null) { -- this.lodestoneWorld = ResourceKey.create(Registries.DIMENSION, ResourceLocation.tryParse(lodestoneWorldString)); -- this.lodestoneX = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_X.BUKKIT); -- this.lodestoneY = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT); -- this.lodestoneZ = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT); -+ // Paper start - use LodestoneTracker type -+ ResourceKey lodestoneWorld = ResourceKey.create(Registries.DIMENSION, ResourceLocation.tryParse(lodestoneWorldString)); -+ int lodestoneX = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_X.BUKKIT); -+ int lodestoneY = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT); -+ int lodestoneZ = (Integer) map.get(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT); -+ this.tracker = new LodestoneTracker(Optional.of(new GlobalPos(lodestoneWorld, new BlockPos(lodestoneX, lodestoneY, lodestoneZ))), true); -+ // Paper end - use LodestoneTracker type - } else { - // legacy - Location lodestone = SerializableMeta.getObject(Location.class, map, CraftMetaCompass.LODESTONE_POS.BUKKIT, true); -@@ -79,21 +67,22 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - this.setLodestone(lodestone); - } - } -- this.tracked = SerializableMeta.getBoolean(map, CraftMetaCompass.LODESTONE_TRACKED.BUKKIT); -+ // Paper start - use LodestoneTracker type -+ final Optional tracked = SerializableMeta.getObjectOptionally(Boolean.class, map, CraftMetaCompass.LODESTONE_TRACKED.BUKKIT, true); -+ final Optional trackedPos = this.tracker != null ? this.tracker.target() : Optional.empty(); -+ tracked.ifPresent(isTracked -> this.tracker = new LodestoneTracker(trackedPos, isTracked)); -+ // Paper end - use LodestoneTracker type - } - - @Override - void applyToItem(CraftMetaItem.Applicator tag) { - super.applyToItem(tag); - -- Optional target = Optional.empty(); -- if (this.lodestoneWorld != null) { -- target = Optional.of(new GlobalPos(this.lodestoneWorld, new BlockPos(this.lodestoneX, this.lodestoneY, this.lodestoneZ))); -- } -- -- if (target.isPresent() || this.hasLodestoneTracked()) { -- tag.put(CraftMetaCompass.LODESTONE_TARGET, new LodestoneTracker(target, this.tracked)); -+ // Paper start - use LodestoneTracker type -+ if (this.tracker != null) { -+ tag.put(CraftMetaCompass.LODESTONE_TARGET, this.tracker); - } -+ // Paper end - use LodestoneTracker type - } - - @Override -@@ -102,7 +91,7 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - } - - boolean isCompassEmpty() { -- return !(this.hasLodestone() || this.hasLodestoneTracked()); -+ return this.tracker == null; // Paper - use LodestoneTracker type - } - - @Override -@@ -113,58 +102,69 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - - @Override - public boolean hasLodestone() { -- return this.lodestoneWorld != null; -+ return this.tracker != null && this.tracker.target().isPresent(); // Paper - use LodestoneTracker type - } - - @Override - public Location getLodestone() { -- if (this.lodestoneWorld == null) { -+ if (this.tracker == null || this.tracker.target().isEmpty()) { // Paper - use LodestoneTracker type - return null; - } -- ServerLevel worldServer = MinecraftServer.getServer().getLevel(this.lodestoneWorld); -+ ServerLevel worldServer = MinecraftServer.getServer().getLevel(this.tracker.target().get().dimension()); // Paper - use LodestoneTracker type - World world = worldServer != null ? worldServer.getWorld() : null; -- return new Location(world, this.lodestoneX, this.lodestoneY, this.lodestoneZ); // world may be null here, if the referenced world is not loaded -+ return org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.tracker.target().get().pos(), world); // world may be null here, if the referenced world is not loaded // Paper - use LodestoneTracker type - } - - @Override - public void setLodestone(Location lodestone) { - Preconditions.checkArgument(lodestone == null || lodestone.getWorld() != null, "world is null"); - if (lodestone == null) { -- this.lodestoneWorld = null; -+ // Paper start - use LodestoneTracker type -+ if (this.tracker != null) { -+ this.tracker = new LodestoneTracker(java.util.Optional.empty(), this.tracker.tracked()); // Paper - use LodestoneTracker type -+ } -+ // Paper end - use LodestoneTracker type - } else { -- this.lodestoneWorld = ((CraftWorld) lodestone.getWorld()).getHandle().dimension(); -- this.lodestoneX = lodestone.getBlockX(); -- this.lodestoneY = lodestone.getBlockY(); -- this.lodestoneZ = lodestone.getBlockZ(); -+ // Paper start - use LodestoneTracker type -+ GlobalPos pos = GlobalPos.of( -+ ((CraftWorld) lodestone.getWorld()).getHandle().dimension(), -+ io.papermc.paper.util.MCUtil.toBlockPosition(lodestone) -+ ); -+ boolean tracked = this.tracker == null || this.tracker.tracked(); -+ this.tracker = new LodestoneTracker(Optional.of(pos), tracked); -+ // Paper end - use LodestoneTracker type - } - } - -- boolean hasLodestoneTracked() { -- return !this.tracked; -- } -- - @Override - public boolean isLodestoneTracked() { -- return this.tracked; -+ return this.tracker != null && this.tracker.tracked(); // Paper - use LodestoneTracker type - } - - @Override - public void setLodestoneTracked(boolean tracked) { -- this.tracked = tracked; -+ final Optional trackedPos = this.tracker != null ? this.tracker.target() : Optional.empty(); // Paper - use LodestoneTracker type -+ this.tracker = new LodestoneTracker(trackedPos, tracked); // Paper - use LodestoneTracker type -+ } -+ -+ // Paper start - Add more lodestone compass methods -+ @Override -+ public boolean isLodestoneCompass() { -+ return this.tracker != null; -+ } -+ -+ @Override -+ public void clearLodestone() { -+ this.tracker = null; - } -+ // Paper end - Add more lodestone compass methods - - @Override - int applyHash() { - final int original; - int hash = original = super.applyHash(); -- if (this.hasLodestone()) { -- hash = 73 * hash + this.lodestoneWorld.hashCode(); -- hash = 73 * hash + this.lodestoneX; -- hash = 73 * hash + this.lodestoneY; -- hash = 73 * hash + this.lodestoneZ; -- } -- if (this.hasLodestoneTracked()) { -- hash = 73 * hash + (this.isLodestoneTracked() ? 1231 : 1237); -+ if (this.isLodestoneCompass()) { -+ hash = 73 * hash + this.tracker.hashCode(); // Paper - use LodestoneTracker type - } - - return original != hash ? CraftMetaCompass.class.hashCode() ^ hash : hash; -@@ -178,10 +178,7 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - if (meta instanceof CraftMetaCompass) { - CraftMetaCompass that = (CraftMetaCompass) meta; - -- return (this.hasLodestone() ? that.hasLodestone() && this.lodestoneWorld.equals(that.lodestoneWorld) -- && this.lodestoneX == that.lodestoneX && this.lodestoneY == that.lodestoneY -- && this.lodestoneZ == that.lodestoneZ : !that.hasLodestone()) -- && this.tracked == that.tracked; -+ return java.util.Objects.equals(this.tracker, that.tracker); // Paper - use LodestoneTracker type - } - return true; - } -@@ -195,14 +192,16 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - Builder serialize(Builder builder) { - super.serialize(builder); - -- if (this.hasLodestone()) { -- builder.put(CraftMetaCompass.LODESTONE_POS_WORLD.BUKKIT, this.lodestoneWorld.location().toString()); -- builder.put(CraftMetaCompass.LODESTONE_POS_X.BUKKIT, this.lodestoneX); -- builder.put(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT, this.lodestoneY); -- builder.put(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT, this.lodestoneZ); -- } -- if (this.hasLodestoneTracked()) { -- builder.put(CraftMetaCompass.LODESTONE_TRACKED.BUKKIT, this.tracked); -+ if (this.isLodestoneCompass()) { // Paper - use LodestoneTracker type -+ // Paper start - use LodestoneTracker type -+ if (this.tracker.target().isPresent()) { -+ builder.put(CraftMetaCompass.LODESTONE_POS_WORLD.BUKKIT, this.tracker.target().get().dimension().location().toString()); -+ builder.put(CraftMetaCompass.LODESTONE_POS_X.BUKKIT, this.tracker.target().get().pos().getX()); -+ builder.put(CraftMetaCompass.LODESTONE_POS_Y.BUKKIT, this.tracker.target().get().pos().getY()); -+ builder.put(CraftMetaCompass.LODESTONE_POS_Z.BUKKIT, this.tracker.target().get().pos().getZ()); -+ } -+ builder.put(CraftMetaCompass.LODESTONE_TRACKED.BUKKIT, this.tracker.tracked()); -+ // Paper end - use LodestoneTracker type - } - - return builder; -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -index 0807c2172c5a4bee675cef265a45a9350e98b880..88ea260fb84a5f8eaab3a23a9a65d0411215a6a1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -@@ -117,7 +117,7 @@ public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta { - @Override - public void addChargedProjectile(ItemStack item) { - Preconditions.checkArgument(item != null, "item"); -- Preconditions.checkArgument(item.getType() == Material.FIREWORK_ROCKET || CraftItemType.bukkitToMinecraft(item.getType()) instanceof ArrowItem, "Item %s is not an arrow or firework rocket", item); -+ Preconditions.checkArgument(!item.isEmpty(), "Item cannot be empty"); // Paper - - if (this.chargedProjectiles == null) { - this.chargedProjectiles = new ArrayList<>(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -index 3f6c5cbbf63631e4b72dc43558651ea94f31ca78..da474a5b963d8e6769d120e9091e60ed0a468a9f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -@@ -98,7 +98,7 @@ public class CraftMetaEntityTag extends CraftMetaItem { - if (meta instanceof CraftMetaEntityTag) { - CraftMetaEntityTag that = (CraftMetaEntityTag) meta; - -- return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : this.entityTag == null; -+ return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : that.entityTag == null; // Paper - } - return true; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -index 566d893a413fd04b99e83dc2da8fe958a48492a8..a944803771d514572f94b4e98a6d4435a009c078 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -@@ -55,7 +55,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - - this.power = that.power; - -- if (that.hasEffects()) { -+ if (that.effects != null) { // Paper - this.effects = new ArrayList<>(that.effects); - } - } -@@ -88,7 +88,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - } - - Iterable effects = SerializableMeta.getObject(Iterable.class, map, CraftMetaFirework.EXPLOSIONS.BUKKIT, true); -- this.safelyAddEffects(effects); -+ this.safelyAddEffects(effects, false); // Paper - limit firework effects - } - - static FireworkEffect getEffect(FireworkExplosion explosion) { -@@ -98,19 +98,14 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - .with(CraftMetaFirework.getEffectType(explosion.shape())); - - IntList colors = explosion.colors(); -- // People using buggy command generators specify a list rather than an int here, so recover with dummy data. -- // Wrong: Colors: [1234] -- // Right: Colors: [I;1234] -- if (colors.isEmpty()) { -- effect.withColor(Color.WHITE); -- } -+ // Paper - this is no longer needed - - for (int color : colors) { -- effect.withColor(Color.fromRGB(color)); -+ effect.withColor(Color.fromRGB(color & 0xFFFFFF)); // Paper - try to keep color component consistent with vanilla (top byte is ignored), this will however change the color component for out of bound color - } - - for (int color : explosion.fadeColors()) { -- effect.withFade(Color.fromRGB(color)); -+ effect.withFade(Color.fromRGB(color & 0xFFFFFF)); // Paper - } - - return effect.build(); -@@ -162,7 +157,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - return !(this.effects == null || this.effects.isEmpty()); - } - -- void safelyAddEffects(Iterable collection) { -+ void safelyAddEffects(Iterable collection, final boolean throwOnOversize) { // Paper - if (collection == null || (collection instanceof Collection && ((Collection) collection).isEmpty())) { - return; - } -@@ -174,6 +169,15 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - - for (Object obj : collection) { - Preconditions.checkArgument(obj instanceof FireworkEffect, "%s in %s is not a FireworkEffect", obj, collection); -+ // Paper start - limit firework effects -+ if (effects.size() + 1 > Fireworks.MAX_EXPLOSIONS) { -+ if (throwOnOversize) { -+ throw new IllegalArgumentException("Cannot have more than " + Fireworks.MAX_EXPLOSIONS + " firework effects"); -+ } else { -+ continue; -+ } -+ } -+ // Paper end - limit firework effects - effects.add((FireworkEffect) obj); - } - } -@@ -215,7 +219,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - } - - boolean isFireworkEmpty() { -- return !(this.hasEffects() || this.hasPower()); -+ return !(this.effects != null || this.hasPower()); // Paper - empty effects list should stay on the item - } - - @Override -@@ -232,7 +236,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - if (meta instanceof CraftMetaFirework that) { - - return (Objects.equals(this.power, that.power)) -- && (this.hasEffects() ? that.hasEffects() && this.effects.equals(that.effects) : !that.hasEffects()); -+ && (this.effects != null ? that.effects != null && this.effects.equals(that.effects) : that.effects == null); // Paper - } - - return true; -@@ -250,7 +254,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - if (this.hasPower()) { - hash = 61 * hash + this.power; - } -- if (this.hasEffects()) { -+ if (this.effects != null) { // Paper - hash = 61 * hash + 13 * this.effects.hashCode(); - } - return hash != original ? CraftMetaFirework.class.hashCode() ^ hash : hash; -@@ -260,7 +264,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - Builder serialize(Builder builder) { - super.serialize(builder); - -- if (this.hasEffects()) { -+ if (this.effects != null) { // Paper - builder.put(CraftMetaFirework.EXPLOSIONS.BUKKIT, ImmutableList.copyOf(this.effects)); - } - -@@ -285,6 +289,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - @Override - public void addEffect(FireworkEffect effect) { - Preconditions.checkArgument(effect != null, "FireworkEffect cannot be null"); -+ Preconditions.checkArgument(this.effects == null || this.effects.size() + 1 <= Fireworks.MAX_EXPLOSIONS, "cannot have more than %s firework effects", Fireworks.MAX_EXPLOSIONS); // Paper - limit firework effects - if (this.effects == null) { - this.effects = new ArrayList(); - } -@@ -294,6 +299,10 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - @Override - public void addEffects(FireworkEffect... effects) { - Preconditions.checkArgument(effects != null, "effects cannot be null"); -+ // Paper start - limit firework effects -+ final int initialSize = this.effects == null ? 0 : this.effects.size(); -+ Preconditions.checkArgument(initialSize + effects.length <= Fireworks.MAX_EXPLOSIONS, "Cannot have more than %s firework effects", Fireworks.MAX_EXPLOSIONS); -+ // Paper end - limit firework effects - if (effects.length == 0) { - return; - } -@@ -312,7 +321,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - @Override - public void addEffects(Iterable effects) { - Preconditions.checkArgument(effects != null, "effects cannot be null"); -- this.safelyAddEffects(effects); -+ this.safelyAddEffects(effects, true); // Paper - limit firework effects - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 13b19adc21ece31476b2980c5bc01a50f15df634..a6e2281bfac94f1e19836d9c8415d8270387b16d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -199,9 +199,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - } - -- static final class Applicator { -+ static abstract class Applicator { // Paper - support updating profile after resolving it - -- private final DataComponentPatch.Builder builder = DataComponentPatch.builder(); -+ final DataComponentPatch.Builder builder = DataComponentPatch.builder(); // Paper - private -> package-private -+ void skullCallback(net.minecraft.world.item.component.ResolvableProfile resolvableProfile) {} // Paper - support updating profile after resolving it - - Applicator put(ItemMetaKeyType key, T value) { - this.builder.set(key.TYPE, value); -@@ -308,7 +309,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - private CraftToolComponent tool; - private CraftEquippableComponent equippable; - private CraftJukeboxComponent jukebox; -- private int damage; -+ private Integer damage; // Paper - may not be set - private Integer maxDamage; - - private static final Set HANDLED_TAGS = Sets.newHashSet(); -@@ -341,7 +342,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.enchantments = new EnchantmentMap(meta.enchantments); // Paper - } - -- if (meta.hasAttributeModifiers()) { -+ if (meta.attributeModifiers != null) { // Paper - this.attributeModifiers = LinkedHashMultimap.create(meta.attributeModifiers); - } - -@@ -390,6 +391,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - - CraftMetaItem(DataComponentPatch tag, Set> extraHandledTags) { // Paper - improve handled tags on type changes -+ // Paper start - properly support data components in BlockEntity -+ this.updateFromPatch(tag, extraHandledTags); -+ } -+ protected final void updateFromPatch(DataComponentPatch tag, Set> extraHandledTags) { -+ // Paper end - properly support data components in BlockEntity - CraftMetaItem.getOrEmpty(tag, CraftMetaItem.NAME).ifPresent((component) -> { - this.displayName = component; - }); -@@ -906,7 +912,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - Map mods = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true); - Multimap result = LinkedHashMultimap.create(); - if (mods == null) { -- return result; -+ return null; // Paper - null is different from an empty map - } - - for (Object obj : mods.keySet()) { -@@ -1037,7 +1043,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - itemTag.put(CraftMetaItem.JUKEBOX_PLAYABLE, this.jukebox.getHandle()); - } - -- if (this.hasDamage()) { -+ if (this.hasDamageValue()) { // Paper - preserve empty/0 damage - itemTag.put(CraftMetaItem.DAMAGE, this.damage); - } - -@@ -1087,7 +1093,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - - void applyEnchantments(Map enchantments, CraftMetaItem.Applicator tag, ItemMetaKeyType key, ItemFlag itemFlag) { -- if (enchantments == null && !this.hasItemFlag(itemFlag)) { -+ if (enchantments == null /*&& !this.hasItemFlag(itemFlag)*/) { // Paper - general item meta fixes - only emit enchantment component if enchantments are defined - return; - } - -@@ -1104,10 +1110,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - - void applyModifiers(Multimap modifiers, CraftMetaItem.Applicator tag) { -- if (modifiers == null || modifiers.isEmpty()) { -- if (this.hasItemFlag(ItemFlag.HIDE_ATTRIBUTES)) { -- tag.put(CraftMetaItem.ATTRIBUTES, new ItemAttributeModifiers(Collections.emptyList(), false)); -- } -+ if (modifiers == null/* || modifiers.isEmpty()*/) { // Paper - empty modifiers has a specific meaning, they should still be saved -+ // Paper - don't save ItemFlag if the underlying data isn't present - return; - } - -@@ -1144,7 +1148,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Overridden - boolean isEmpty() { -- return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper -+ return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamageValue() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper - } - - // Paper start -@@ -1240,6 +1244,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public void lore(final List lore) { -+ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines - this.lore = lore != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(lore) : null; - } - // Paper end -@@ -1298,7 +1303,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - @Override - public void removeEnchantments() { - if (this.hasEnchants()) { -- this.enchantments.clear(); -+ this.enchantments = null; // Paper - Correctly clear enchantments - } - } - -@@ -1364,6 +1369,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - // Paper end - @Override - public void setLore(List lore) { -+ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines - if (lore == null || lore.isEmpty()) { - this.lore = null; - } else { -@@ -1379,6 +1385,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - // Paper start - @Override - public void setLoreComponents(List lore) { -+ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines - if (lore == null) { - this.lore = null; - } else { -@@ -1596,6 +1603,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public void setUseRemainder(ItemStack useRemainder) { -+ Preconditions.checkArgument(useRemainder == null || !useRemainder.isEmpty(), "Item cannot be empty"); // Paper - this.useRemainder = useRemainder; - } - -@@ -1606,7 +1614,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public UseCooldownComponent getUseCooldown() { -- return (this.hasUseCooldown()) ? new CraftUseCooldownComponent(this.useCooldown) : new CraftUseCooldownComponent(new UseCooldown(0)); -+ return (this.hasUseCooldown()) ? new CraftUseCooldownComponent(this.useCooldown) : new CraftUseCooldownComponent(new UseCooldown(1.0F)); // Paper - Create a valid use_cooldown component - } - - @Override -@@ -1656,7 +1664,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public void setEquippable(EquippableComponent equippable) { -- this.equippable = (equippable == null) ? null : new CraftEquippableComponent((CraftEquippableComponent) this.equippable); -+ this.equippable = (equippable == null) ? null : new CraftEquippableComponent((CraftEquippableComponent) equippable); // Paper - } - - @Override -@@ -1692,7 +1700,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public Multimap getAttributeModifiers(@Nullable EquipmentSlot slot) { -- this.checkAttributeList(); -+ if (this.attributeModifiers == null) return LinkedHashMultimap.create(); // Paper - don't change the components - SetMultimap result = LinkedHashMultimap.create(); - for (Map.Entry entry : this.attributeModifiers.entries()) { - if (entry.getValue().getSlot() == null || entry.getValue().getSlot() == slot) { -@@ -1705,6 +1713,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - @Override - public Collection getAttributeModifiers(@Nonnull Attribute attribute) { - Preconditions.checkNotNull(attribute, "Attribute cannot be null"); -+ if (this.attributeModifiers == null) return null; // Paper - fix NPE - return this.attributeModifiers.containsKey(attribute) ? ImmutableList.copyOf(this.attributeModifiers.get(attribute)) : null; - } - -@@ -1712,22 +1721,33 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - public boolean addAttributeModifier(@Nonnull Attribute attribute, @Nonnull AttributeModifier modifier) { - Preconditions.checkNotNull(attribute, "Attribute cannot be null"); - Preconditions.checkNotNull(modifier, "AttributeModifier cannot be null"); -- this.checkAttributeList(); -+ if (this.attributeModifiers != null) { // Paper - for (Map.Entry entry : this.attributeModifiers.entries()) { - Preconditions.checkArgument(!(entry.getValue().getKey().equals(modifier.getKey()) && entry.getKey() == attribute), "Cannot register AttributeModifier. Modifier is already applied! %s", modifier); // Paper - attribute modifiers with same namespaced key but on different attributes are fine - } -+ } // Paper -+ this.checkAttributeList(); // Paper - moved down - return this.attributeModifiers.put(attribute, modifier); - } - - @Override - public void setAttributeModifiers(@Nullable Multimap attributeModifiers) { -- if (attributeModifiers == null || attributeModifiers.isEmpty()) { -+ // Paper start - distinguish between null and empty -+ if (attributeModifiers == null) { -+ this.attributeModifiers = null; -+ return; -+ } -+ if (attributeModifiers.isEmpty()) { -+ // Paper end - distinguish between null and empty - this.attributeModifiers = LinkedHashMultimap.create(); - return; - } - -- this.checkAttributeList(); -- this.attributeModifiers.clear(); -+ // Paper start - fix modifiers meta -+ if (this.attributeModifiers != null) { -+ this.attributeModifiers.clear(); -+ } -+ // Paper end - - Iterator> iterator = attributeModifiers.entries().iterator(); - while (iterator.hasNext()) { -@@ -1737,6 +1757,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - iterator.remove(); - continue; - } -+ this.checkAttributeList(); // Paper - moved down - this.attributeModifiers.put(next.getKey(), next.getValue()); - } - } -@@ -1744,13 +1765,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - @Override - public boolean removeAttributeModifier(@Nonnull Attribute attribute) { - Preconditions.checkNotNull(attribute, "Attribute cannot be null"); -- this.checkAttributeList(); -+ if (this.attributeModifiers == null) return false; // Paper - return !this.attributeModifiers.removeAll(attribute).isEmpty(); - } - - @Override - public boolean removeAttributeModifier(@Nullable EquipmentSlot slot) { -- this.checkAttributeList(); -+ if (this.attributeModifiers == null) return false; // Paper - int removed = 0; - Iterator> iter = this.attributeModifiers.entries().iterator(); - -@@ -1770,7 +1791,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - public boolean removeAttributeModifier(@Nonnull Attribute attribute, @Nonnull AttributeModifier modifier) { - Preconditions.checkNotNull(attribute, "Attribute cannot be null"); - Preconditions.checkNotNull(modifier, "AttributeModifier cannot be null"); -- this.checkAttributeList(); -+ if (this.attributeModifiers == null) return false; // Paper - int removed = 0; - Iterator> iter = this.attributeModifiers.entries().iterator(); - -@@ -1792,7 +1813,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public String getAsString() { -- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); -+ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {}; // Paper - support updating profile after resolving it - this.applyToItem(tag); - DataComponentPatch patch = tag.build(); - net.minecraft.nbt.Tag nbt = DataComponentPatch.CODEC.encodeStart(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), patch).getOrThrow(); -@@ -1801,7 +1822,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public String getAsComponentString() { -- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); -+ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {}; // Paper - this.applyToItem(tag); - DataComponentPatch patch = tag.build(); - -@@ -1841,6 +1862,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - if (first == null || second == null) { - return false; - } -+ if (first.isEmpty() && second.isEmpty()) return true; // Paper - empty modifiers are equivalent - for (Map.Entry entry : first.entries()) { - if (!second.containsEntry(entry.getKey(), entry.getValue())) { - return false; -@@ -1856,19 +1878,33 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public boolean hasDamage() { -- return this.damage > 0; -+ return this.damage != null && this.damage > 0; // Paper - null check - } - - @Override - public int getDamage() { -- return this.damage; -+ return this.damage == null ? 0 : this.damage; // Paper - null check - } - - @Override - public void setDamage(int damage) { -+ Preconditions.checkArgument(damage >= 0, "Damage cannot be negative"); // Paper -+ Preconditions.checkArgument(!this.hasMaxDamage() || damage <= this.maxDamage, "Damage cannot exceed max damage"); // Paper - this.damage = damage; - } - -+ // Paper start - preserve empty/0 damage -+ @Override -+ public boolean hasDamageValue() { -+ return this.damage != null; -+ } -+ -+ @Override -+ public void resetDamage() { -+ this.damage = null; -+ } -+ // Paper end - preserve empty/0 damage -+ - @Override - public boolean hasMaxDamage() { - return this.maxDamage != null; -@@ -1882,6 +1918,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public void setMaxDamage(Integer maxDamage) { -+ Preconditions.checkArgument(maxDamage == null || maxDamage > 0, "Max damage should be positive"); // Paper - this.maxDamage = maxDamage; - } - -@@ -1914,7 +1951,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - && (this.hasEnchantable() ? that.hasEnchantable() && this.enchantableValue.equals(that.enchantableValue) : !that.hasEnchantable()) - && (this.hasBlockData() ? that.hasBlockData() && this.blockData.equals(that.blockData) : !that.hasBlockData()) - && (this.hasRepairCost() ? that.hasRepairCost() && this.repairCost == that.repairCost : !that.hasRepairCost()) -- && (this.hasAttributeModifiers() ? that.hasAttributeModifiers() && CraftMetaItem.compareModifiers(this.attributeModifiers, that.attributeModifiers) : !that.hasAttributeModifiers()) -+ && (this.attributeModifiers != null ? that.attributeModifiers != null && CraftMetaItem.compareModifiers(this.attributeModifiers, that.attributeModifiers) : that.attributeModifiers == null) // Paper - track only null modifiers - && (this.unhandledTags.equals(that.unhandledTags)) - && (this.removedTags.equals(that.removedTags)) - && (Objects.equals(this.customTag, that.customTag)) -@@ -1935,7 +1972,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - && (this.hasTool() ? that.hasTool() && this.tool.equals(that.tool) : !that.hasTool()) - && (this.hasEquippable() ? that.hasEquippable() && this.equippable.equals(that.equippable) : !that.hasEquippable()) - && (this.hasJukeboxPlayable() ? that.hasJukeboxPlayable() && this.jukebox.equals(that.jukebox) : !that.hasJukeboxPlayable()) -- && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) -+ && (Objects.equals(this.damage, that.damage)) // Paper - preserve empty/0 damage - && (this.hasMaxDamage() ? that.hasMaxDamage() && this.maxDamage.equals(that.maxDamage) : !that.hasMaxDamage()) - && (this.canPlaceOnPredicates != null ? that.canPlaceOnPredicates != null && this.canPlaceOnPredicates.equals(that.canPlaceOnPredicates) : that.canPlaceOnPredicates == null) // Paper - && (this.canBreakPredicates != null ? that.canBreakPredicates != null && this.canBreakPredicates.equals(that.canBreakPredicates) : that.canBreakPredicates == null) // Paper -@@ -1988,9 +2025,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - hash = 61 * hash + (this.hasTool() ? this.tool.hashCode() : 0); - hash = 61 * hash + (this.hasJukeboxPlayable() ? this.jukebox.hashCode() : 0); - hash = 61 * hash + (this.hasEquippable() ? this.equippable.hashCode() : 0); -- hash = 61 * hash + (this.hasDamage() ? this.damage : 0); -- hash = 61 * hash + (this.hasMaxDamage() ? 1231 : 1237); -- hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); -+ hash = 61 * hash + (this.hasDamageValue() ? this.damage : -1); // Paper - preserve empty/0 damage -+ hash = 61 * hash + (this.hasMaxDamage() ? this.maxDamage.hashCode() : 0); // Paper - max damage is not a boolean -+ hash = 61 * hash + (this.attributeModifiers != null ? this.attributeModifiers.hashCode() : 0); // Paper - track only null attributes - hash = 61 * hash + (this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates.hashCode() : 0); // Paper - hash = 61 * hash + (this.canBreakPredicates != null ? this.canBreakPredicates.hashCode() : 0); // Paper - hash = 61 * hash + this.version; -@@ -2011,7 +2048,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - if (this.enchantments != null) { - clone.enchantments = new EnchantmentMap(this.enchantments); // Paper - } -- if (this.hasAttributeModifiers()) { -+ if (this.attributeModifiers != null) { // Paper - clone.attributeModifiers = LinkedHashMultimap.create(this.attributeModifiers); - } - if (this.customTag != null) { -@@ -2178,7 +2215,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - builder.put(CraftMetaItem.JUKEBOX_PLAYABLE.BUKKIT, this.jukebox); - } - -- if (this.hasDamage()) { -+ if (this.hasDamageValue()) { // Paper - preserve empty/0 damage - builder.put(CraftMetaItem.DAMAGE.BUKKIT, this.damage); - } - -@@ -2279,7 +2316,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - - static void serializeModifiers(Multimap modifiers, ImmutableMap.Builder builder, ItemMetaKey key) { -- if (modifiers == null || modifiers.isEmpty()) { -+ if (modifiers == null/* || modifiers.isEmpty()*/) { // Paper - null and an empty map have different behaviors - return; - } - -@@ -2361,7 +2398,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - // Paper start - improve checking handled tags - @org.jetbrains.annotations.VisibleForTesting - public static final Map, Set>> HANDLED_DCTS_PER_TYPE = new HashMap<>(); -- private static final Set> DEFAULT_HANDLED_DCTS = Set.of( -+ protected static final Set> DEFAULT_HANDLED_DCTS = Set.of( - CraftMetaItem.NAME.TYPE, - CraftMetaItem.ITEM_NAME.TYPE, - CraftMetaItem.LORE.TYPE, -@@ -2437,7 +2474,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - // Paper end - improve checking handled data component types - - protected static Optional getOrEmpty(DataComponentPatch tag, ItemMetaKeyType type) { -- Optional result = tag.get(type.TYPE); -+ // Paper start -+ return getOrEmpty(tag, type.TYPE); -+ } -+ protected static Optional getOrEmpty(final DataComponentPatch tag, final DataComponentType type) { -+ Optional result = tag.get(type); -+ // Paper end - - return (result != null) ? result : Optional.empty(); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -index e76749bffaf5a0bbd3a8d35f882edcc3598351b9..49889026661fb2a558e14569324016d637de27a0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -@@ -18,16 +18,30 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - - static final ItemMetaKeyType COLOR = new ItemMetaKeyType<>(DataComponents.DYED_COLOR, "color"); - -- private Color color = DEFAULT_LEATHER_COLOR; -+ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) - - CraftMetaLeatherArmor(CraftMetaItem meta) { - super(meta); -- CraftMetaLeatherArmor.readColor(this, meta); -+ // Paper start -+ if (!(meta instanceof CraftMetaLeatherArmor leatherMeta)) { -+ return; -+ } -+ -+ this.color = leatherMeta.color; -+ // Paper end - } - - CraftMetaLeatherArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper - super(tag, extraHandledDcts); // Paper -- CraftMetaLeatherArmor.readColor(this, tag); -+ // Paper start -+ getOrEmpty(tag, CraftMetaLeatherArmor.COLOR).ifPresent((dyedItemColor) -> { -+ if (!dyedItemColor.showInTooltip()) { -+ this.addItemFlags(ItemFlag.HIDE_DYE); -+ } -+ -+ this.color = dyedItemColor.rgb(); -+ }); -+ // Paper end - } - - CraftMetaLeatherArmor(Map map) { -@@ -38,7 +52,11 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - @Override - void applyToItem(CraftMetaItem.Applicator itemTag) { - super.applyToItem(itemTag); -- CraftMetaLeatherArmor.applyColor(this, itemTag); -+ // Paper start -+ if (this.hasColor()) { -+ itemTag.put(CraftMetaLeatherArmor.COLOR, new DyedItemColor(this.color, !this.hasItemFlag(ItemFlag.HIDE_DYE))); -+ } -+ // Paper end - } - - @Override -@@ -66,16 +84,16 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - - @Override - public Color getColor() { -- return this.color; -+ return this.color == null ? DEFAULT_LEATHER_COLOR : Color.fromRGB(this.color & 0xFFFFFF); // Paper - } - - @Override - public void setColor(Color color) { -- this.color = color == null ? DEFAULT_LEATHER_COLOR : color; -+ this.color = color == null ? null : color.asRGB(); // Paper - } - - boolean hasColor() { -- return CraftMetaLeatherArmor.hasColor(this); -+ return this.color != null; // Paper - } - - @Override -@@ -95,7 +113,7 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - if (meta instanceof CraftMetaLeatherArmor) { - CraftMetaLeatherArmor that = (CraftMetaLeatherArmor) meta; - -- return this.color.equals(that.color); -+ return this.hasColor() ? that.hasColor() && this.color.equals(that.color) : !that.hasColor(); // Paper - allow null - } - return true; - } -@@ -115,14 +133,16 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - return original != hash ? CraftMetaLeatherArmor.class.hashCode() ^ hash : hash; - } - -+ @io.papermc.paper.annotation.DoNotUse // Paper - static void readColor(LeatherArmorMeta meta, CraftMetaItem other) { - if (!(other instanceof CraftMetaLeatherArmor armorMeta)) { - return; - } - -- meta.setColor(armorMeta.color); -+ // meta.setColor(armorMeta.color); // Paper - commented out, color is now an integer and cannot be passed to setColor - } - -+ @io.papermc.paper.annotation.DoNotUse // Paper - static void readColor(LeatherArmorMeta meta, DataComponentPatch tag) { - getOrEmpty(tag, CraftMetaLeatherArmor.COLOR).ifPresent((dyedItemColor) -> { - if (!dyedItemColor.showInTooltip()) { -@@ -145,6 +165,7 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - return !DEFAULT_LEATHER_COLOR.equals(meta.getColor()); - } - -+ @io.papermc.paper.annotation.DoNotUse // Paper - static void applyColor(LeatherArmorMeta meta, CraftMetaItem.Applicator tag) { - if (CraftMetaLeatherArmor.hasColor(meta)) { - tag.put(CraftMetaLeatherArmor.COLOR, new DyedItemColor(meta.getColor().asRGB(), !meta.hasItemFlag(ItemFlag.HIDE_DYE))); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -index 149356981e586e4f67d4543d3df94a2ea99333fc..06c72ed83dab9492b70bfd13f7f9c1a4cbef9e2f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -@@ -29,7 +29,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { - - private Integer mapId; - private byte scaling = CraftMetaMap.SCALING_EMPTY; -- private Color color; -+ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) - - CraftMetaMap(CraftMetaItem meta) { - super(meta); -@@ -57,7 +57,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { - - getOrEmpty(tag, CraftMetaMap.MAP_COLOR).ifPresent((mapColor) -> { - try { -- this.color = Color.fromRGB(mapColor.rgb()); -+ this.color = mapColor.rgb(); // Paper - } catch (IllegalArgumentException ex) { - // Invalid colour - } -@@ -101,7 +101,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { - } - - if (this.hasColor()) { -- tag.put(CraftMetaMap.MAP_COLOR, new MapItemColor(this.color.asRGB())); -+ tag.put(CraftMetaMap.MAP_COLOR, new MapItemColor(this.color)); // Paper - } - } - -@@ -121,6 +121,7 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { - - @Override - public int getMapId() { -+ Preconditions.checkState(this.hasMapId(), "Item does not have map associated - check hasMapId() first!"); // Paper - fix NPE - return this.mapId; - } - -@@ -181,12 +182,12 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { - - @Override - public Color getColor() { -- return this.color; -+ return this.color == null ? null : Color.fromRGB(this.color & 0xFFFFFF); // Paper - } - - @Override - public void setColor(Color color) { -- this.color = color; -+ this.color = color == null ? null : color.asRGB(); // Paper - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -index b118d8ecb505d187c02bb158f14df333f487a87f..fa1d1a7f37aadf2750f03a0e215fb25fa948f9aa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -@@ -70,6 +70,7 @@ public class CraftMetaOminousBottle extends CraftMetaItem implements OminousBott - - @Override - public int getAmplifier() { -+ Preconditions.checkState(this.hasAmplifier(), "'ominous_bottle_amplifier' data component is absent. Check hasAmplifier first!"); // Paper - fix NPE - return this.ominousBottleAmplifier; - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -index 6f0eebcaffa20337cf5a7f8485f891c690d948ae..18dc2e83dab0821e5129bd68361de189363823b3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -@@ -38,7 +38,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - - private PotionType type; - private List customEffects; -- private Color color; -+ private Integer color; // Paper - keep color component consistent with vanilla (top byte is ignored) - private String customName; - - CraftMetaPotion(CraftMetaItem meta) { -@@ -63,7 +63,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - - potionContents.customColor().ifPresent((customColor) -> { - try { -- this.color = Color.fromRGB(customColor); -+ this.color = customColor; // Paper - } catch (IllegalArgumentException ex) { - // Invalid colour - } -@@ -132,7 +132,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - } - - Optional> defaultPotion = (this.hasBasePotionType()) ? Optional.of(CraftPotionType.bukkitToMinecraftHolder(this.type)) : Optional.empty(); -- Optional potionColor = (this.hasColor()) ? Optional.of(this.color.asRGB()) : Optional.empty(); -+ Optional potionColor = (this.hasColor()) ? Optional.of(this.color) : Optional.empty(); // Paper - Optional customName = Optional.ofNullable(this.customName); - - List effectList = new ArrayList<>(); -@@ -297,12 +297,12 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - - @Override - public Color getColor() { -- return this.color; -+ return this.color == null ? null : Color.fromRGB(this.color & 0xFFFFFF); // Paper - } - - @Override - public void setColor(Color color) { -- this.color = color; -+ this.color = color == null ? null : color.asRGB(); // Paper - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -index 967d8940aec0065bce496d5d7a8c73de5733bd2c..e229ca6acb6dbc3185f326f6653b3d66d835a9e5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -@@ -28,17 +28,29 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - - static final ItemMetaKeyType BASE_COLOR = new ItemMetaKeyType<>(DataComponents.BASE_COLOR, "Base", "base-color"); - -- private Banner banner; -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ private @org.jetbrains.annotations.Nullable List patterns; -+ private @org.jetbrains.annotations.Nullable DyeColor baseColor; -+ -+ // An empty pattern list is the same as the default on the Shield item, and will hence not be present in the data components of the stack. -+ private boolean hasPatterns() { -+ return this.patterns != null && !this.patterns.isEmpty(); -+ } -+ // Paper end - general item meta fixes - decoupled base colour and patterns - - CraftMetaShield(CraftMetaItem meta) { - super(meta); - - if (meta instanceof CraftMetaShield craftMetaShield) { -- if (craftMetaShield.banner != null) { -- this.banner = (Banner) craftMetaShield.banner.copy(); -- } -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ if (craftMetaShield.patterns != null) this.patterns = new ArrayList<>(craftMetaShield.getPatterns()); -+ if (craftMetaShield.baseColor != null) this.baseColor = craftMetaShield.baseColor; -+ // Paper end - general item meta fixes - decoupled base colour and patterns - } else if (meta instanceof CraftMetaBlockState state && state.hasBlockState() && state.getBlockState() instanceof Banner banner) { -- this.banner = (Banner) banner.copy(); -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ this.patterns = banner.getPatterns(); -+ this.baseColor = banner.getBaseColor(); -+ // Paper end - general item meta fixes - decoupled base colour and patterns - } - } - -@@ -46,7 +58,7 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - super(tag, extraHandledDcts); // Paper - improve checking handled tags in item meta - - getOrEmpty(tag, CraftMetaShield.BASE_COLOR).ifPresent((color) -> { -- this.banner = CraftMetaShield.getBlockState(DyeColor.getByWoolData((byte) color.getId())); -+ this.baseColor = DyeColor.getByWoolData((byte) color.getId()); // Paper - general item meta fixes - decoupled base colour and patterns - }); - - getOrEmpty(tag, CraftMetaBanner.PATTERNS).ifPresent((entityTag) -> { -@@ -68,7 +80,7 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - - String baseColor = SerializableMeta.getString(map, CraftMetaShield.BASE_COLOR.BUKKIT, true); - if (baseColor != null) { -- this.banner = CraftMetaShield.getBlockState(DyeColor.valueOf(baseColor)); -+ this.baseColor = DyeColor.valueOf(baseColor); // Paper - general item meta fixes - decoupled base colour and patterns - } - - Iterable rawPatternList = SerializableMeta.getObject(Iterable.class, map, CraftMetaBanner.PATTERNS.BUKKIT, true); -@@ -86,13 +98,14 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - void applyToItem(CraftMetaItem.Applicator tag) { - super.applyToItem(tag); - -- if (this.banner != null) { -- tag.put(CraftMetaShield.BASE_COLOR, net.minecraft.world.item.DyeColor.byId(this.banner.getBaseColor().getWoolData())); -- -- if (this.banner.numberOfPatterns() > 0) { -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ if (this.baseColor != null) tag.put(CraftMetaShield.BASE_COLOR, net.minecraft.world.item.DyeColor.byId(this.baseColor.getWoolData())); -+ if (this.patterns != null && !this.patterns.isEmpty()) { -+ { -+ // Paper end - general item meta fixes - decoupled base colour and patterns - List newPatterns = new ArrayList<>(); - -- for (Pattern p : this.banner.getPatterns()) { -+ for (Pattern p : this.patterns) { // Paper - general item meta fixes - decoupled base colour and patterns - newPatterns.add(new BannerPatternLayers.Layer(CraftPatternType.bukkitToMinecraftHolder(p.getPattern()), net.minecraft.world.item.DyeColor.byId(p.getColor().getWoolData()))); - } - -@@ -103,108 +116,84 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - - @Override - public List getPatterns() { -- if (this.banner == null) { -+ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns - return new ArrayList<>(); - } - -- return this.banner.getPatterns(); -+ return new ArrayList<>(this.patterns); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public void setPatterns(List patterns) { -- if (this.banner == null) { -- if (patterns.isEmpty()) { -- return; -- } -- -- this.banner = CraftMetaShield.getBlockState(null); -- } -- -- this.banner.setPatterns(patterns); -+ this.patterns = new ArrayList<>(patterns); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public void addPattern(Pattern pattern) { -- if (this.banner == null) { -- this.banner = CraftMetaShield.getBlockState(null); -- } -- -- this.banner.addPattern(pattern); -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ if (this.patterns == null) this.patterns = new ArrayList<>(); -+ this.patterns.add(pattern); -+ // Paper end - general item meta fixes - decoupled base colour and patterns - } - - @Override - public Pattern getPattern(int i) { -- if (this.banner == null) { -+ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns - throw new IndexOutOfBoundsException(i); - } - -- return this.banner.getPattern(i); -+ return this.patterns.get(i); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public Pattern removePattern(int i) { -- if (this.banner == null) { -+ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns - throw new IndexOutOfBoundsException(i); - } - -- return this.banner.removePattern(i); -+ return this.patterns.remove(i); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public void setPattern(int i, Pattern pattern) { -- if (this.banner == null) { -+ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns - throw new IndexOutOfBoundsException(i); - } - -- this.banner.setPattern(i, pattern); -+ this.patterns.set(i, pattern); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public int numberOfPatterns() { -- if (this.banner == null) { -+ if (this.patterns == null) { // Paper - general item meta fixes - decoupled base colour and patterns - return 0; - } - -- return this.banner.numberOfPatterns(); -+ return this.patterns.size(); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public DyeColor getBaseColor() { -- if (this.banner == null) { -- return null; -- } -- -- return this.banner.getBaseColor(); -+ return this.baseColor; // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public void setBaseColor(DyeColor baseColor) { -- if (baseColor == null) { -- if (this.banner.numberOfPatterns() > 0) { -- this.banner.setBaseColor(DyeColor.WHITE); -- } else { -- this.banner = null; -- } -- } else { -- if (this.banner == null) { -- this.banner = CraftMetaShield.getBlockState(baseColor); -- } -- -- this.banner.setBaseColor(baseColor); -- } -+ this.baseColor = baseColor; // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { - super.serialize(builder); - -- if (this.banner != null) { -- builder.put(CraftMetaShield.BASE_COLOR.BUKKIT, this.banner.getBaseColor().toString()); -- -- if (this.banner.numberOfPatterns() > 0) { -- builder.put(CraftMetaBanner.PATTERNS.BUKKIT, this.banner.getPatterns()); -- } -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ if (this.baseColor != null) { -+ builder.put(CraftMetaShield.BASE_COLOR.BUKKIT, this.baseColor.toString()); -+ } -+ if (hasPatterns()) { -+ builder.put(CraftMetaBanner.PATTERNS.BUKKIT, this.patterns); - } -+ // Paper end - general item meta fixes - decoupled base colour and patterns - - return builder; - } -@@ -213,8 +202,13 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - int applyHash() { - final int original; - int hash = original = super.applyHash(); -- if (this.banner != null) { -- hash = 61 * hash + this.banner.hashCode(); -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ if (this.baseColor != null) { -+ hash = 61 * hash + this.baseColor.hashCode(); -+ } -+ if (hasPatterns()) { -+ hash = 61 * hash + this.patterns.hashCode(); -+ // Paper end - general item meta fixes - decoupled base colour and patterns - } - return original != hash ? CraftMetaShield.class.hashCode() ^ hash : hash; - } -@@ -225,29 +219,33 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - return false; - } - if (meta instanceof CraftMetaShield that) { -- return Objects.equal(this.banner, that.banner); -+ return Objects.equal(this.baseColor, that.baseColor) && Objects.equal(this.patterns, that.patterns); // Paper - general item meta fixes - decoupled base colour and patterns - } - return true; - } - - @Override - boolean notUncommon(CraftMetaItem meta) { -- return super.notUncommon(meta) && (meta instanceof CraftMetaShield || this.banner == null); -+ return super.notUncommon(meta) && (meta instanceof CraftMetaShield || (this.baseColor == null && !hasPatterns())); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - boolean isEmpty() { -- return super.isEmpty() && this.banner == null; -+ return super.isEmpty() && this.baseColor == null && !hasPatterns(); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public boolean hasBlockState() { -- return this.banner != null; -+ return this.baseColor != null || hasPatterns(); // Paper - general item meta fixes - decoupled base colour and patterns - } - - @Override - public BlockState getBlockState() { -- return (this.banner != null) ? this.banner.copy() : CraftMetaShield.getBlockState(null); -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ final Banner banner = CraftMetaShield.getBlockState(this.baseColor); -+ if (this.patterns != null) banner.setPatterns(this.patterns); -+ return banner; -+ // Paper end - general item meta fixes - decoupled base colour and patterns - } - - @Override -@@ -255,13 +253,18 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - Preconditions.checkArgument(blockState != null, "blockState must not be null"); - Preconditions.checkArgument(blockState instanceof Banner, "Invalid blockState"); - -- this.banner = (Banner) blockState; -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ final Banner banner = (Banner) blockState; -+ this.baseColor = banner.getBaseColor(); -+ this.patterns = banner.getPatterns(); -+ // Paper end - general item meta fixes - decoupled base colour and patterns - } - - // Paper start - add method to clear block state - @Override - public void clearBlockState() { -- this.banner = null; -+ this.baseColor = null; -+ this.patterns = null; - } - // Paper end - add method to clear block state - -@@ -275,9 +278,10 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - @Override - public CraftMetaShield clone() { - CraftMetaShield meta = (CraftMetaShield) super.clone(); -- if (this.banner != null) { -- meta.banner = (Banner) this.banner.copy(); -- } -+ // Paper start - general item meta fixes - decoupled base colour and patterns -+ meta.baseColor = this.baseColor; -+ meta.patterns = this.patterns == null ? null : new ArrayList<>(this.patterns); -+ // Paper start - general item meta fixes - decoupled base colour and patterns - return meta; - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -index 302906467b12189e21633369c005736863f46dd5..5a4e5b8736ad2e2084e757e9d2034044e177d8f0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -@@ -112,10 +112,10 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { - // Fill in textures - PlayerProfile ownerProfile = new CraftPlayerProfile(this.profile); // getOwnerProfile may return null - if (ownerProfile.getTextures().isEmpty()) { -- ownerProfile.update().thenAccept((filledProfile) -> { -+ ownerProfile.update().thenAcceptAsync((filledProfile) -> { // Paper - run on main thread - this.setOwnerProfile(filledProfile); -- tag.put(CraftMetaSkull.SKULL_PROFILE, this.profile); -- }); -+ tag.skullCallback(this.profile); // Paper - actually set profile on itemstack -+ }, ((org.bukkit.craftbukkit.CraftServer) org.bukkit.Bukkit.getServer()).getServer()); // Paper - run on main thread - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -index 8ddf091b3ff1262b6c97e8fe72e0a80db5e1037d..be92ccda66f514459773916cc16b6c230e863444 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -@@ -121,6 +121,7 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { - - @Override - public EntitySnapshot getSpawnedEntity() { -+ if (this.entityTag == null) return null; // Paper - fix NPE - return CraftEntitySnapshot.create(this.entityTag); - } - -@@ -138,7 +139,7 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { - if (meta instanceof CraftMetaSpawnEgg) { - CraftMetaSpawnEgg that = (CraftMetaSpawnEgg) meta; - -- return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : this.entityTag == null; -+ return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : that.entityTag == null; // Paper - } - return true; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -index 17705059b81942e4df43a4a5180092e09c985ade..80e6b85a107d5236edba99540cb5074e2dc1485a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -@@ -120,6 +120,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB - - @Override - public DyeColor getPatternColor() { -+ com.google.common.base.Preconditions.checkState(this.hasVariant(), "This bucket doesn't have variant, check hasVariant first!"); // Paper - fix NPE - return CraftTropicalFish.getPatternColor(this.variant); - } - -@@ -133,6 +134,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB - - @Override - public DyeColor getBodyColor() { -+ com.google.common.base.Preconditions.checkState(this.hasVariant(), "This bucket doesn't have variant, check hasVariant first!"); // Paper - fix NPE - return CraftTropicalFish.getBodyColor(this.variant); - } - -@@ -146,6 +148,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB - - @Override - public TropicalFish.Pattern getPattern() { -+ com.google.common.base.Preconditions.checkState(this.hasVariant(), "This bucket doesn't have variant, check hasVariant first!"); // Paper - fix NPE - return CraftTropicalFish.getPattern(this.variant); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java -index e00b757d6059715e8697428008fcb3e6e7abbe2e..dcf02bd0f7f4c67f5ab98003cc932b960704eef1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java -@@ -136,4 +136,21 @@ public final class SerializableMeta implements ConfigurationSerializable { - } - throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz); - } -+ -+ // Paper start - General ItemMeta Fixes -+ public static java.util.Optional getObjectOptionally(Class clazz, Map map, Object field, boolean nullable) { -+ final Object object = map.get(field); -+ -+ if (clazz.isInstance(object)) { -+ return java.util.Optional.of(clazz.cast(object)); -+ } -+ if (object == null) { -+ if (!nullable) { -+ throw new NoSuchElementException(map + " does not contain " + field); -+ } -+ return java.util.Optional.empty(); -+ } -+ throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz); -+ } -+ // Paper end - General ItemMeta Fixes - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java -index 1f1589bcdb9e3abde7d25eac65326df1e7ed75ab..9b4c2502e45af4e7a58ff352f0f99c34d233f755 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java -@@ -170,7 +170,7 @@ public final class CraftEquippableComponent implements EquippableComponent { - - @Override - public void setAllowedEntities(Tag tag) { -- Preconditions.checkArgument(tag instanceof CraftEntityTag, "tag must be an entity tag"); -+ Preconditions.checkArgument(tag == null || tag instanceof CraftEntityTag, "tag must be an entity tag"); // Paper - - this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.model(), this.handle.cameraOverlay(), - (tag != null) ? Optional.of(((CraftEntityTag) tag).getHandle()) : Optional.empty(), -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java -index 9a4a1d903c22e9d2a0cbda95ceb8b1dcfb29112e..4f7914f96207feda67cd910213bb624df4802a06 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java -@@ -106,6 +106,7 @@ public final class CraftToolComponent implements ToolComponent { - public ToolRule addRule(Material block, Float speed, Boolean correctForDrops) { - Preconditions.checkArgument(block != null, "block must not be null"); - Preconditions.checkArgument(block.isBlock(), "block must be a block type, given %s", block.getKey()); -+ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed - - Holder.Reference nmsBlock = CraftBlockType.bukkitToMinecraft(block).builtInRegistryHolder(); - return this.addRule(HolderSet.direct(nmsBlock), speed, correctForDrops); -@@ -113,6 +114,7 @@ public final class CraftToolComponent implements ToolComponent { - - @Override - public ToolRule addRule(Collection blocks, Float speed, Boolean correctForDrops) { -+ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed - List> nmsBlocks = new ArrayList<>(blocks.size()); - - for (Material material : blocks) { -@@ -126,6 +128,7 @@ public final class CraftToolComponent implements ToolComponent { - @Override - public ToolRule addRule(Tag tag, Float speed, Boolean correctForDrops) { - Preconditions.checkArgument(tag instanceof CraftBlockTag, "tag must be a block tag"); -+ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed - return this.addRule(((CraftBlockTag) tag).getHandle(), speed, correctForDrops); - } - -@@ -258,6 +261,7 @@ public final class CraftToolComponent implements ToolComponent { - - @Override - public void setSpeed(Float speed) { -+ Preconditions.checkArgument(speed == null || speed > 0, "speed must be positive"); // Paper - validate speed - this.handle = new Tool.Rule(this.handle.blocks(), Optional.ofNullable(speed), this.handle.correctForDrops()); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java -index 952e7fa022161d1d21ba1a4f43abe5ee221dee4b..0f86ff23cc6a2f617fc5ef67e576e1e3cb29034c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftUseCooldownComponent.java -@@ -55,7 +55,7 @@ public final class CraftUseCooldownComponent implements UseCooldownComponent { - - @Override - public void setCooldownSeconds(float eatSeconds) { -- Preconditions.checkArgument(eatSeconds >= 0, "eatSeconds cannot be less than 0"); -+ Preconditions.checkArgument(eatSeconds > 0, "eatSeconds must be positive"); // Paper - - this.handle = new UseCooldown(eatSeconds, this.handle.cooldownGroup()); - } -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -index 9cc1ef5c9221dd7d2069b280f0c91ce9439a995a..1c80fe7549d70ae16c7b755c22752549261f072a 100644 ---- a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -@@ -94,7 +94,7 @@ public class DeprecatedItemMetaCustomValueTest { - public void testNBTTagStoring() { - CraftMetaItem itemMeta = this.createComplexItemMeta(); - -- CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); -+ CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator() {}; // Paper - itemMeta.applyToItem(compound); - - assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -index 130c4500a5e854480962c8f720b1df4c67d43c33..f33b49915d1f1f0838c49ac943e8d4d619450f6b 100644 ---- a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -@@ -128,7 +128,7 @@ public class PersistentDataContainerTest { - public void testNBTTagStoring() { - CraftMetaItem itemMeta = this.createComplexItemMeta(); - -- CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); -+ CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator() {}; // Paper - itemMeta.applyToItem(compound); - - assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper -@@ -474,7 +474,7 @@ public class PersistentDataContainerTest { - assertEquals(List.of(), container.get(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings())); - - // Write and read the entire container to NBT -- final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator(); -+ final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator() {}; // Paper - craftItem.applyToItem(storage); - - final CraftMetaItem readItem = new CraftMetaItem(storage.build(), null); // Paper diff --git a/patches/server/0954-More-Chest-Block-API.patch b/patches/server/0954-More-Chest-Block-API.patch new file mode 100644 index 0000000000..d7c00f61e1 --- /dev/null +++ b/patches/server/0954-More-Chest-Block-API.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 1 May 2024 08:22:13 +0300 +Subject: [PATCH] More Chest Block API + +== AT == +public net.minecraft.world.level.block.ChestBlock isBlockedChestByBlock(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z + +diff --git a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java +index b376f7d3b632d6aaea5c4d93382238074559d56a..ef0d469176ee74b6bb5f9e9cc508735145fda5b8 100644 +--- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java +@@ -83,7 +83,7 @@ public class EnderChestBlock extends AbstractChestBlock i + PlayerEnderChestContainer playerEnderChestContainer = player.getEnderChestInventory(); + if (playerEnderChestContainer != null && world.getBlockEntity(pos) instanceof EnderChestBlockEntity enderChestBlockEntity) { + BlockPos blockPos = pos.above(); +- if (world.getBlockState(blockPos).isRedstoneConductor(world, blockPos)) { ++ if (world.getBlockState(blockPos).isRedstoneConductor(world, blockPos)) { // Paper - diff on change; make sure that EnderChest#isBlocked uses the same logic + return InteractionResult.SUCCESS; + } else { + if (world instanceof ServerLevel serverLevel) { +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +index 6e98a00d526b734992ce39b15768c5820dce4ca8..cc7bf4d39b834fba472bc163226a01a0cd4b6010 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +@@ -99,4 +99,29 @@ public class CraftChest extends CraftLootable implements Chest + return getTileEntity().openersCounter.opened; + } + // Paper end - More Lidded Block API ++ ++ // Paper start - More Chest Block API ++ @Override ++ public boolean isBlocked() { ++ // Method mimics vanilla logic in ChestBlock and DoubleBlockCombiner when trying to open chest's container ++ if (!isPlaced()) { ++ return false; ++ } ++ net.minecraft.world.level.LevelAccessor world = getWorldHandle(); ++ if (ChestBlock.isChestBlockedAt(world, getPosition())) { ++ return true; ++ } ++ if (ChestBlock.getBlockType(this.data) == net.minecraft.world.level.block.DoubleBlockCombiner.BlockType.SINGLE) { ++ return false; ++ } ++ net.minecraft.core.Direction direction = ChestBlock.getConnectedDirection(this.data); ++ net.minecraft.core.BlockPos neighbourBlockPos = getPosition().relative(direction); ++ BlockState neighbourBlockState = world.getBlockStateIfLoaded(neighbourBlockPos); ++ return neighbourBlockState != null ++ && neighbourBlockState.is(this.data.getBlock()) ++ && ChestBlock.getBlockType(neighbourBlockState) != net.minecraft.world.level.block.DoubleBlockCombiner.BlockType.SINGLE ++ && ChestBlock.getConnectedDirection(neighbourBlockState) == direction.getOpposite() ++ && ChestBlock.isChestBlockedAt(world, neighbourBlockPos); ++ } ++ // Paper end - More Chest Block API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java +index b64adbba3e52d32d439e64a243cb74f3fbca2ce3..f45ee675a10729845bf376fa95e648b23b9aac12 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java +@@ -58,4 +58,13 @@ public class CraftEnderChest extends CraftBlockEntityState -Date: Wed, 1 May 2024 08:22:13 +0300 -Subject: [PATCH] More Chest Block API - -== AT == -public net.minecraft.world.level.block.ChestBlock isBlockedChestByBlock(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z - -diff --git a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -index b376f7d3b632d6aaea5c4d93382238074559d56a..ef0d469176ee74b6bb5f9e9cc508735145fda5b8 100644 ---- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -@@ -83,7 +83,7 @@ public class EnderChestBlock extends AbstractChestBlock i - PlayerEnderChestContainer playerEnderChestContainer = player.getEnderChestInventory(); - if (playerEnderChestContainer != null && world.getBlockEntity(pos) instanceof EnderChestBlockEntity enderChestBlockEntity) { - BlockPos blockPos = pos.above(); -- if (world.getBlockState(blockPos).isRedstoneConductor(world, blockPos)) { -+ if (world.getBlockState(blockPos).isRedstoneConductor(world, blockPos)) { // Paper - diff on change; make sure that EnderChest#isBlocked uses the same logic - return InteractionResult.SUCCESS; - } else { - if (world instanceof ServerLevel serverLevel) { -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -index 6e98a00d526b734992ce39b15768c5820dce4ca8..cc7bf4d39b834fba472bc163226a01a0cd4b6010 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -@@ -99,4 +99,29 @@ public class CraftChest extends CraftLootable implements Chest - return getTileEntity().openersCounter.opened; - } - // Paper end - More Lidded Block API -+ -+ // Paper start - More Chest Block API -+ @Override -+ public boolean isBlocked() { -+ // Method mimics vanilla logic in ChestBlock and DoubleBlockCombiner when trying to open chest's container -+ if (!isPlaced()) { -+ return false; -+ } -+ net.minecraft.world.level.LevelAccessor world = getWorldHandle(); -+ if (ChestBlock.isChestBlockedAt(world, getPosition())) { -+ return true; -+ } -+ if (ChestBlock.getBlockType(this.data) == net.minecraft.world.level.block.DoubleBlockCombiner.BlockType.SINGLE) { -+ return false; -+ } -+ net.minecraft.core.Direction direction = ChestBlock.getConnectedDirection(this.data); -+ net.minecraft.core.BlockPos neighbourBlockPos = getPosition().relative(direction); -+ BlockState neighbourBlockState = world.getBlockStateIfLoaded(neighbourBlockPos); -+ return neighbourBlockState != null -+ && neighbourBlockState.is(this.data.getBlock()) -+ && ChestBlock.getBlockType(neighbourBlockState) != net.minecraft.world.level.block.DoubleBlockCombiner.BlockType.SINGLE -+ && ChestBlock.getConnectedDirection(neighbourBlockState) == direction.getOpposite() -+ && ChestBlock.isChestBlockedAt(world, neighbourBlockPos); -+ } -+ // Paper end - More Chest Block API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java -index b64adbba3e52d32d439e64a243cb74f3fbca2ce3..f45ee675a10729845bf376fa95e648b23b9aac12 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java -@@ -58,4 +58,13 @@ public class CraftEnderChest extends CraftBlockEntityState +Date: Thu, 9 May 2024 15:11:34 +0200 +Subject: [PATCH] Print data component type on encoding error + + +diff --git a/src/main/java/net/minecraft/core/component/DataComponentPatch.java b/src/main/java/net/minecraft/core/component/DataComponentPatch.java +index 9de958d769a52a8df794988781f8601a4e6a73a4..9dec1c74d10f82636b7176e8f725b8acd1b52e4f 100644 +--- a/src/main/java/net/minecraft/core/component/DataComponentPatch.java ++++ b/src/main/java/net/minecraft/core/component/DataComponentPatch.java +@@ -144,7 +144,13 @@ public final class DataComponentPatch { + } + + private static void encodeComponent(RegistryFriendlyByteBuf buf, DataComponentType type, Object value) { ++ // Paper start - codec errors of random anonymous classes are useless ++ try { + type.streamCodec().encode(buf, (T) value); // CraftBukkit - decompile error ++ } catch (final Exception e) { ++ throw new RuntimeException("Error encoding component " + type, e); ++ } ++ // Paper end - codec errors of random anonymous classes are useless + } + }; + private static final String REMOVED_PREFIX = "!"; diff --git a/patches/server/0956-Brigadier-based-command-API.patch b/patches/server/0956-Brigadier-based-command-API.patch new file mode 100644 index 0000000000..a0f076f9b2 --- /dev/null +++ b/patches/server/0956-Brigadier-based-command-API.patch @@ -0,0 +1,2829 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Mon, 1 Aug 2022 22:50:34 -0400 +Subject: [PATCH] Brigadier based command API + +== AT == +public net.minecraft.commands.arguments.blocks.BlockInput tag +public net.minecraft.commands.arguments.DimensionArgument ERROR_INVALID_VALUE +public net.minecraft.server.ReloadableServerResources registryLookup +public net.minecraft.server.ReloadableServerResources + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +index 4b4f812eb13d5f03bcf3f8724d8aa8dbbc724e8b..a4d5d7017e0be79844b996de85a63cad5f8488bc 100644 +--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java ++++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java +@@ -459,7 +459,7 @@ public class CommandDispatcher { + } + + private String getSmartUsage(final CommandNode node, final S source, final boolean optional, final boolean deep) { +- if (!node.canUse(source)) { ++ if (source != null && !node.canUse(source)) { // Paper + return null; + } + +@@ -473,7 +473,7 @@ public class CommandDispatcher { + final String redirect = node.getRedirect() == this.root ? "..." : "-> " + node.getRedirect().getUsageText(); + return self + CommandDispatcher.ARGUMENT_SEPARATOR + redirect; + } else { +- final Collection> children = node.getChildren().stream().filter(c -> c.canUse(source)).collect(Collectors.toList()); ++ final Collection> children = node.getChildren().stream().filter(c -> source == null || c.canUse(source)).collect(Collectors.toList()); // Paper + if (children.size() == 1) { + final String usage = this.getSmartUsage(children.iterator().next(), source, childOptional, childOptional); + if (usage != null) { +diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +index 1f4963bf4681a771130abc1da179819626ecfc1f..03ce8a2abb6dceaa922dcce7f3adbc228bbde4bc 100644 +--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java ++++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +@@ -35,6 +35,8 @@ public abstract class CommandNode implements Comparable> { + private final boolean forks; + private Command command; + public CommandNode clientNode; // Paper - Brigadier API ++ public CommandNode unwrappedCached = null; // Paper - Brigadier Command API ++ public CommandNode wrappedCached = null; // Paper - Brigadier Command API + // CraftBukkit start + public void removeCommand(String name) { + this.children.remove(name); +@@ -203,4 +205,11 @@ public abstract class CommandNode implements Comparable> { + } + + public abstract Collection getExamples(); ++ // Paper start - Brigadier Command API ++ public void clearAll() { ++ this.children.clear(); ++ this.literals.clear(); ++ this.arguments.clear(); ++ } ++ // Paper end - Brigadier Command API + } +diff --git a/src/main/java/io/papermc/paper/brigadier/NullCommandSender.java b/src/main/java/io/papermc/paper/brigadier/NullCommandSender.java +new file mode 100644 +index 0000000000000000000000000000000000000000..367ef7e0769537e8c13c7fd818a1249e15a28a65 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/brigadier/NullCommandSender.java +@@ -0,0 +1,151 @@ ++package io.papermc.paper.brigadier; ++ ++import java.util.Set; ++import java.util.UUID; ++import net.kyori.adventure.text.Component; ++import net.md_5.bungee.api.chat.BaseComponent; ++import org.bukkit.Bukkit; ++import org.bukkit.Server; ++import org.bukkit.command.CommandSender; ++import org.bukkit.permissions.PermissibleBase; ++import org.bukkit.permissions.Permission; ++import org.bukkit.permissions.PermissionAttachment; ++import org.bukkit.permissions.PermissionAttachmentInfo; ++import org.bukkit.plugin.Plugin; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++@DefaultQualifier(NonNull.class) ++public final class NullCommandSender implements CommandSender { ++ ++ public static final CommandSender INSTANCE = new NullCommandSender(); ++ ++ private NullCommandSender() { ++ } ++ ++ @Override ++ public void sendMessage(final String message) { ++ } ++ ++ @Override ++ public void sendMessage(final String... messages) { ++ } ++ ++ @Override ++ public void sendMessage(@Nullable final UUID sender, final String message) { ++ } ++ ++ @Override ++ public void sendMessage(@Nullable final UUID sender, final String... messages) { ++ } ++ ++ @SuppressWarnings("ConstantValue") ++ @Override ++ public Server getServer() { ++ final @Nullable Server server = Bukkit.getServer(); ++ if (server == null) { ++ throw new UnsupportedOperationException("The server has not been created yet, you cannot access it at this time from the 'null' CommandSender"); ++ } ++ return server; ++ } ++ ++ @Override ++ public String getName() { ++ return ""; ++ } ++ ++ private final Spigot spigot = new Spigot(); ++ @Override ++ public Spigot spigot() { ++ return this.spigot; ++ } ++ ++ public final class Spigot extends CommandSender.Spigot { ++ ++ @Override ++ public void sendMessage(@NotNull final BaseComponent component) { ++ } ++ ++ @Override ++ public void sendMessage(@NonNull final @NotNull BaseComponent... components) { ++ } ++ ++ @Override ++ public void sendMessage(@Nullable final UUID sender, @NotNull final BaseComponent component) { ++ } ++ ++ @Override ++ public void sendMessage(@Nullable final UUID sender, @NonNull final @NotNull BaseComponent... components) { ++ } ++ } ++ ++ @Override ++ public Component name() { ++ return Component.empty(); ++ } ++ ++ @Override ++ public boolean isPermissionSet(final String name) { ++ return false; ++ } ++ ++ @Override ++ public boolean isPermissionSet(final Permission perm) { ++ return false; ++ } ++ ++ @Override ++ public boolean hasPermission(final String name) { ++ return true; ++ } ++ ++ @Override ++ public boolean hasPermission(final Permission perm) { ++ return true; ++ } ++ ++ @Override ++ public PermissionAttachment addAttachment(final Plugin plugin, final String name, final boolean value) { ++ throw new UnsupportedOperationException("Cannot add attachments to the 'null' CommandSender"); ++ } ++ ++ @Override ++ public PermissionAttachment addAttachment(final Plugin plugin) { ++ throw new UnsupportedOperationException("Cannot add attachments to the 'null' CommandSender"); ++ } ++ ++ @Override ++ public @Nullable PermissionAttachment addAttachment(final Plugin plugin, final String name, final boolean value, final int ticks) { ++ throw new UnsupportedOperationException("Cannot add attachments to the 'null' CommandSender"); ++ } ++ ++ @Override ++ public @Nullable PermissionAttachment addAttachment(final Plugin plugin, final int ticks) { ++ throw new UnsupportedOperationException("Cannot add attachments to the 'null' CommandSender"); ++ } ++ ++ @Override ++ public void removeAttachment(final PermissionAttachment attachment) { ++ throw new UnsupportedOperationException("Cannot add attachments to the 'null' CommandSender"); ++ } ++ ++ @Override ++ public void recalculatePermissions() { ++ } ++ ++ @Override ++ public Set getEffectivePermissions() { ++ throw new UnsupportedOperationException("Cannot remove attachments from the 'null' CommandSender"); ++ } ++ ++ @Override ++ public boolean isOp() { ++ return true; ++ } ++ ++ @Override ++ public void setOp(final boolean value) { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java b/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java +deleted file mode 100644 +index dd6012b6a097575b2d1471be5069eccee4537c0a..0000000000000000000000000000000000000000 +--- a/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java ++++ /dev/null +@@ -1,30 +0,0 @@ +-package io.papermc.paper.brigadier; +- +-import com.mojang.brigadier.Message; +-import io.papermc.paper.adventure.PaperAdventure; +-import net.kyori.adventure.text.Component; +-import net.kyori.adventure.text.ComponentLike; +-import net.minecraft.network.chat.ComponentUtils; +-import org.checkerframework.checker.nullness.qual.NonNull; +- +-import static java.util.Objects.requireNonNull; +- +-public enum PaperBrigadierProviderImpl implements PaperBrigadierProvider { +- INSTANCE; +- +- PaperBrigadierProviderImpl() { +- PaperBrigadierProvider.initialize(this); +- } +- +- @Override +- public @NonNull Message message(final @NonNull ComponentLike componentLike) { +- requireNonNull(componentLike, "componentLike"); +- return PaperAdventure.asVanilla(componentLike.asComponent()); +- } +- +- @Override +- public @NonNull Component componentFromMessage(final @NonNull Message message) { +- requireNonNull(message, "message"); +- return PaperAdventure.asAdventure(ComponentUtils.fromMessage(message)); +- } +-} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/ApiMirrorRootNode.java b/src/main/java/io/papermc/paper/command/brigadier/ApiMirrorRootNode.java +new file mode 100644 +index 0000000000000000000000000000000000000000..23525592d880f340745a28c956fa38d3e4057231 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/ApiMirrorRootNode.java +@@ -0,0 +1,253 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.google.common.collect.Collections2; ++import com.mojang.brigadier.CommandDispatcher; ++import com.mojang.brigadier.arguments.ArgumentType; ++import com.mojang.brigadier.arguments.BoolArgumentType; ++import com.mojang.brigadier.arguments.DoubleArgumentType; ++import com.mojang.brigadier.arguments.FloatArgumentType; ++import com.mojang.brigadier.arguments.IntegerArgumentType; ++import com.mojang.brigadier.arguments.LongArgumentType; ++import com.mojang.brigadier.arguments.StringArgumentType; ++import com.mojang.brigadier.context.CommandContext; ++import com.mojang.brigadier.suggestion.SuggestionProvider; ++import com.mojang.brigadier.suggestion.SuggestionsBuilder; ++import com.mojang.brigadier.tree.ArgumentCommandNode; ++import com.mojang.brigadier.tree.CommandNode; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++import com.mojang.brigadier.tree.RootCommandNode; ++import io.papermc.paper.command.brigadier.argument.CustomArgumentType; ++import io.papermc.paper.command.brigadier.argument.VanillaArgumentProviderImpl; ++import io.papermc.paper.command.brigadier.argument.WrappedArgumentCommandNode; ++import java.lang.reflect.Method; ++import java.util.Collection; ++import java.util.Set; ++import net.minecraft.commands.synchronization.ArgumentTypeInfos; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * This root command node is responsible for wrapping around vanilla's dispatcher. ++ *

++ * The reason for this is conversion is we do NOT want there to be NMS types ++ * in the api. This allows us to reconstruct the nodes to be more api friendly, while ++ * we can then unwrap it when needed and convert them to NMS types. ++ *

++ * Command nodes such as vanilla (those without a proper "api node") ++ * will be assigned a {@link ShadowBrigNode}. ++ * This prevents certain parts of it (children) from being accessed by the api. ++ */ ++public abstract class ApiMirrorRootNode extends RootCommandNode { ++ ++ /** ++ * Represents argument types that are allowed to exist in the api. ++ * These typically represent primitives that don't need to be wrapped ++ * by NMS. ++ */ ++ private static final Set>> ARGUMENT_WHITELIST = Set.of( ++ BoolArgumentType.class, ++ DoubleArgumentType.class, ++ FloatArgumentType.class, ++ IntegerArgumentType.class, ++ LongArgumentType.class, ++ StringArgumentType.class ++ ); ++ ++ public static void validatePrimitiveType(ArgumentType type) { ++ if (ARGUMENT_WHITELIST.contains(type.getClass())) { ++ if (!ArgumentTypeInfos.isClassRecognized(type.getClass())) { ++ throw new IllegalArgumentException("This whitelisted primitive argument type is not recognized by the server!"); ++ } ++ } else if (!(type instanceof VanillaArgumentProviderImpl.NativeWrapperArgumentType nativeWrapperArgumentType) || !ArgumentTypeInfos.isClassRecognized(nativeWrapperArgumentType.nativeNmsArgumentType().getClass())) { ++ throw new IllegalArgumentException("Custom argument type was passed, this was not a recognized type to send to the client! You must only pass vanilla arguments or primitive brig args in the wrapper!"); ++ } ++ } ++ ++ public abstract CommandDispatcher getDispatcher(); ++ ++ /** ++ * This logic is responsible for unwrapping an API node to be supported by NMS. ++ * See the method implementation for detailed steps. ++ * ++ * @param maybeWrappedNode api provided node / node to be "wrapped" ++ * @return wrapped node ++ */ ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ private @NotNull CommandNode unwrapNode(final CommandNode maybeWrappedNode) { ++ /* ++ If the type is a shadow node we can assume that the type that it represents is an already supported NMS node. ++ This is because these are typically minecraft command nodes. ++ */ ++ if (maybeWrappedNode instanceof final ShadowBrigNode shadowBrigNode) { ++ return (CommandNode) shadowBrigNode.getHandle(); ++ } ++ ++ /* ++ This node already has had an unwrapped node created, so we can assume that it's safe to reuse that cached copy. ++ */ ++ if (maybeWrappedNode.unwrappedCached != null) { ++ return maybeWrappedNode.unwrappedCached; ++ } ++ ++ // convert the pure brig node into one compatible with the nms dispatcher ++ return this.convertFromPureBrigNode(maybeWrappedNode); ++ } ++ ++ private @NotNull CommandNode convertFromPureBrigNode(final CommandNode pureNode) { ++ /* ++ Logic for converting a node. ++ */ ++ final CommandNode converted; ++ if (pureNode instanceof final LiteralCommandNode node) { ++ /* ++ Remap the literal node, we only have to account ++ for the redirect in this case. ++ */ ++ converted = this.simpleUnwrap(node); ++ } else if (pureNode instanceof final ArgumentCommandNode pureArgumentNode) { ++ final ArgumentType pureArgumentType = pureArgumentNode.getType(); ++ /* ++ Check to see if this argument type is a wrapped type, if so we know that ++ we can unwrap the node to get an NMS type. ++ */ ++ if (pureArgumentType instanceof final CustomArgumentType customArgumentType) { ++ final SuggestionProvider suggestionProvider; ++ try { ++ final Method listSuggestions = customArgumentType.getClass().getMethod("listSuggestions", CommandContext.class, SuggestionsBuilder.class); ++ if (listSuggestions.getDeclaringClass() != CustomArgumentType.class) { ++ suggestionProvider = customArgumentType::listSuggestions; ++ } else { ++ suggestionProvider = null; ++ } ++ } catch (final NoSuchMethodException ex) { ++ throw new IllegalStateException("Could not determine if the custom argument type " + customArgumentType + " overrides listSuggestions", ex); ++ } ++ ++ converted = this.unwrapArgumentWrapper(pureArgumentNode, customArgumentType, customArgumentType.getNativeType(), suggestionProvider); ++ } else if (pureArgumentType instanceof final VanillaArgumentProviderImpl.NativeWrapperArgumentType nativeWrapperArgumentType) { ++ converted = this.unwrapArgumentWrapper(pureArgumentNode, nativeWrapperArgumentType, nativeWrapperArgumentType, null); // "null" for suggestion provider so it uses the argument type's suggestion provider ++ ++ /* ++ If it's not a wrapped type, it either has to be a primitive or an already ++ defined NMS type. ++ This method allows us to check if this is recognized by vanilla. ++ */ ++ } else if (ArgumentTypeInfos.isClassRecognized(pureArgumentType.getClass())) { ++ // Allow any type of argument, as long as it's recognized by the client (but in most cases, this should be API only types) ++ // Previously we only allowed whitelisted types. ++ converted = this.simpleUnwrap(pureArgumentNode); ++ } else { ++ // Unknown argument type was passed ++ throw new IllegalArgumentException("Custom unknown argument type was passed, should be wrapped inside an CustomArgumentType."); ++ } ++ } else { ++ throw new IllegalArgumentException("Unknown command node passed. Don't know how to unwrap this."); ++ } ++ ++ // Store unwrapped node before unwrapping children to avoid infinite recursion in cyclic redirects. ++ converted.wrappedCached = pureNode; ++ pureNode.unwrappedCached = converted; ++ ++ /* ++ Add the children to the node, unwrapping each child in the process. ++ */ ++ for (final CommandNode child : pureNode.getChildren()) { ++ converted.addChild(this.unwrapNode(child)); ++ } ++ ++ return converted; ++ } ++ ++ /** ++ * This logic is responsible for rewrapping a node. ++ * If a node was unwrapped in the past, it should have a wrapped type ++ * stored in its cache. ++ *

++ * However, if it doesn't seem to have a wrapped version we will return ++ * a {@link ShadowBrigNode} instead. This supports being unwrapped/wrapped while ++ * preventing the API from accessing it unsafely. ++ * ++ * @param unwrapped argument node ++ * @return wrapped node ++ */ ++ private @Nullable CommandNode wrapNode(@Nullable final CommandNode unwrapped) { ++ if (unwrapped == null) { ++ return null; ++ } ++ ++ /* ++ This was most likely created by API and has a wrapped variant, ++ so we can return this safely. ++ */ ++ if (unwrapped.wrappedCached != null) { ++ return unwrapped.wrappedCached; ++ } ++ ++ /* ++ We don't know the type of this, or where this came from. ++ Return a shadow, where we will allow the api to handle this but have ++ restrictive access. ++ */ ++ CommandNode shadow = new ShadowBrigNode(unwrapped); ++ unwrapped.wrappedCached = shadow; ++ return shadow; ++ } ++ ++ /** ++ * Nodes added to this dispatcher must be unwrapped ++ * in order to be added to the NMS dispatcher. ++ * ++ * @param node node to add ++ */ ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ @Override ++ public void addChild(CommandNode node) { ++ CommandNode convertedNode = this.unwrapNode(node); ++ this.getDispatcher().getRoot().addChild(convertedNode); ++ } ++ ++ /** ++ * Gets the children for the vanilla dispatcher, ++ * ensuring that all are wrapped. ++ * ++ * @return wrapped children ++ */ ++ @Override ++ public Collection> getChildren() { ++ return Collections2.transform(this.getDispatcher().getRoot().getChildren(), this::wrapNode); ++ } ++ ++ @Override ++ public CommandNode getChild(String name) { ++ return this.wrapNode(this.getDispatcher().getRoot().getChild(name)); ++ } ++ ++ // These are needed for bukkit... we should NOT allow this ++ @Override ++ public void removeCommand(String name) { ++ this.getDispatcher().getRoot().removeCommand(name); ++ } ++ ++ @Override ++ public void clearAll() { ++ this.getDispatcher().getRoot().clearAll(); ++ } ++ ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ private CommandNode unwrapArgumentWrapper(final ArgumentCommandNode pureNode, final ArgumentType pureArgumentType, final ArgumentType possiblyWrappedNativeArgumentType, @Nullable SuggestionProvider argumentTypeSuggestionProvider) { ++ validatePrimitiveType(possiblyWrappedNativeArgumentType); ++ final CommandNode redirectNode = pureNode.getRedirect() == null ? null : this.unwrapNode(pureNode.getRedirect()); ++ // If there is already a custom suggestion provider, ignore the suggestion provider from the argument type ++ final SuggestionProvider suggestionProvider = pureNode.getCustomSuggestions() != null ? pureNode.getCustomSuggestions() : argumentTypeSuggestionProvider; ++ ++ final ArgumentType nativeArgumentType = possiblyWrappedNativeArgumentType instanceof final VanillaArgumentProviderImpl.NativeWrapperArgumentType nativeWrapperArgumentType ? nativeWrapperArgumentType.nativeNmsArgumentType() : possiblyWrappedNativeArgumentType; ++ return new WrappedArgumentCommandNode<>(pureNode.getName(), pureArgumentType, nativeArgumentType, pureNode.getCommand(), pureNode.getRequirement(), redirectNode, pureNode.getRedirectModifier(), pureNode.isFork(), suggestionProvider); ++ } ++ ++ private CommandNode simpleUnwrap(final CommandNode node) { ++ return node.createBuilder() ++ .redirect(node.getRedirect() == null ? null : this.unwrapNode(node.getRedirect())) ++ .build(); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerImpl.java b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b33c6cf2366568641e6f2fd7f74fb74f6ea0145 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerImpl.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.mojang.brigadier.Message; ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.text.Component; ++import net.minecraft.network.chat.ComponentUtils; ++import org.jetbrains.annotations.NotNull; ++ ++public final class MessageComponentSerializerImpl implements MessageComponentSerializer { ++ ++ @Override ++ public @NotNull Component deserialize(@NotNull Message input) { ++ return PaperAdventure.asAdventure(ComponentUtils.fromMessage(input)); ++ } ++ ++ @Override ++ public @NotNull Message serialize(@NotNull Component component) { ++ return PaperAdventure.asVanilla(component); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/PaperBrigadier.java b/src/main/java/io/papermc/paper/command/brigadier/PaperBrigadier.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4acf7c3bcfbe61431bfbfa3c8addb33f671eb498 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/PaperBrigadier.java +@@ -0,0 +1,73 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.mojang.brigadier.CommandDispatcher; ++import com.mojang.brigadier.tree.CommandNode; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++import io.papermc.paper.command.brigadier.bukkit.BukkitBrigForwardingMap; ++import io.papermc.paper.command.brigadier.bukkit.BukkitCommandNode; ++import net.minecraft.commands.CommandSource; ++import net.minecraft.commands.Commands; ++import net.minecraft.network.chat.CommonComponents; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.world.phys.Vec2; ++import net.minecraft.world.phys.Vec3; ++import org.bukkit.Bukkit; ++import org.bukkit.Server; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandMap; ++import org.bukkit.craftbukkit.command.VanillaCommandWrapper; ++ ++import java.util.Map; ++ ++public final class PaperBrigadier { ++ ++ @SuppressWarnings("DataFlowIssue") ++ static final net.minecraft.commands.CommandSourceStack DUMMY = new net.minecraft.commands.CommandSourceStack( ++ CommandSource.NULL, ++ Vec3.ZERO, ++ Vec2.ZERO, ++ null, ++ 4, ++ "", ++ CommonComponents.EMPTY, ++ null, ++ null ++ ); ++ ++ @SuppressWarnings({"unchecked", "rawtypes"}) ++ public static Command wrapNode(CommandNode node) { ++ if (!(node instanceof LiteralCommandNode)) { ++ throw new IllegalArgumentException("Unsure how to wrap a " + node); ++ } ++ ++ if (!(node instanceof PluginCommandNode pluginCommandNode)) { ++ return new VanillaCommandWrapper(null, node); ++ } ++ CommandNode argumentCommandNode = node; ++ if (argumentCommandNode.getRedirect() != null) { ++ argumentCommandNode = argumentCommandNode.getRedirect(); ++ } ++ ++ Map, String> map = PaperCommands.INSTANCE.getDispatcherInternal().getSmartUsage(argumentCommandNode, DUMMY); ++ String usage = map.isEmpty() ? pluginCommandNode.getUsageText() : pluginCommandNode.getUsageText() + " " + String.join("\n" + pluginCommandNode.getUsageText() + " ", map.values()); ++ return new PluginVanillaCommandWrapper(pluginCommandNode.getName(), pluginCommandNode.getDescription(), usage, pluginCommandNode.getAliases(), node, pluginCommandNode.getPlugin()); ++ } ++ ++ /* ++ Previously, Bukkit used one command dispatcher and ignored minecraft's reloading logic. ++ ++ In order to allow for legacy commands to be properly added, we will iterate through previous bukkit commands ++ in the old dispatcher and re-register them. ++ */ ++ @SuppressWarnings({"unchecked", "rawtypes"}) ++ public static void moveBukkitCommands(Commands before, Commands after) { ++ CommandDispatcher erasedDispatcher = before.getDispatcher(); ++ ++ for (Object node : erasedDispatcher.getRoot().getChildren()) { ++ if (node instanceof CommandNode commandNode && commandNode.getCommand() instanceof BukkitCommandNode.BukkitBrigCommand) { ++ after.getDispatcher().getRoot().removeCommand(((CommandNode) node).getName()); // Remove already existing commands ++ after.getDispatcher().getRoot().addChild((CommandNode) node); ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/PaperCommandSourceStack.java b/src/main/java/io/papermc/paper/command/brigadier/PaperCommandSourceStack.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1b1642f306771f029e6214a2e2ebebb6ae6abc3e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/PaperCommandSourceStack.java +@@ -0,0 +1,63 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; ++import net.minecraft.world.level.Level; ++import net.minecraft.world.phys.Vec2; ++import net.minecraft.world.phys.Vec3; ++import org.bukkit.Location; ++import org.bukkit.command.CommandSender; ++import org.bukkit.entity.Entity; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public interface PaperCommandSourceStack extends CommandSourceStack, BukkitBrigadierCommandSource { ++ ++ net.minecraft.commands.CommandSourceStack getHandle(); ++ ++ @Override ++ default @NotNull Location getLocation() { ++ Vec2 rot = this.getHandle().getRotation(); ++ Vec3 pos = this.getHandle().getPosition(); ++ Level level = this.getHandle().getLevel(); ++ ++ return new Location(level.getWorld(), pos.x, pos.y, pos.z, rot.y, rot.x); ++ } ++ ++ @Override ++ @NotNull ++ default CommandSender getSender() { ++ return this.getHandle().getBukkitSender(); ++ } ++ ++ @Override ++ @Nullable ++ default Entity getExecutor() { ++ net.minecraft.world.entity.Entity nmsEntity = this.getHandle().getEntity(); ++ if (nmsEntity == null) { ++ return null; ++ } ++ ++ return nmsEntity.getBukkitEntity(); ++ } ++ ++ // OLD METHODS ++ @Override ++ default org.bukkit.entity.Entity getBukkitEntity() { ++ return this.getExecutor(); ++ } ++ ++ @Override ++ default org.bukkit.World getBukkitWorld() { ++ return this.getLocation().getWorld(); ++ } ++ ++ @Override ++ default org.bukkit.Location getBukkitLocation() { ++ return this.getLocation(); ++ } ++ ++ @Override ++ default CommandSender getBukkitSender() { ++ return this.getSender(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java b/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java +new file mode 100644 +index 0000000000000000000000000000000000000000..95d3b42cbe2184b0a04d941f27f7a6e643ef59be +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java +@@ -0,0 +1,204 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.google.common.base.Preconditions; ++import com.mojang.brigadier.CommandDispatcher; ++import com.mojang.brigadier.arguments.StringArgumentType; ++import com.mojang.brigadier.builder.LiteralArgumentBuilder; ++import com.mojang.brigadier.suggestion.SuggestionsBuilder; ++import com.mojang.brigadier.tree.CommandNode; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++import io.papermc.paper.command.brigadier.bukkit.BukkitCommandNode; ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar; ++import java.util.ArrayList; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Locale; ++import java.util.Set; ++import net.minecraft.commands.CommandBuildContext; ++import org.apache.commons.lang3.ArrayUtils; ++import org.apache.commons.lang3.StringUtils; ++import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Unmodifiable; ++ ++import static java.util.Objects.requireNonNull; ++ ++@DefaultQualifier(NonNull.class) ++public class PaperCommands implements Commands, PaperRegistrar { ++ ++ public static final PaperCommands INSTANCE = new PaperCommands(); ++ ++ private @Nullable LifecycleEventOwner currentContext; ++ private @MonotonicNonNull CommandDispatcher dispatcher; ++ private @MonotonicNonNull CommandBuildContext buildContext; ++ private boolean invalid = false; ++ ++ @Override ++ public void setCurrentContext(final @Nullable LifecycleEventOwner context) { ++ this.currentContext = context; ++ } ++ ++ public void setDispatcher(final net.minecraft.commands.Commands commands, final CommandBuildContext commandBuildContext) { ++ this.invalid = false; ++ this.dispatcher = new CommandDispatcher<>(new ApiMirrorRootNode() { ++ @Override ++ public CommandDispatcher getDispatcher() { ++ return commands.getDispatcher(); ++ } ++ }); ++ this.buildContext = commandBuildContext; ++ } ++ ++ public void setValid() { ++ this.invalid = false; ++ } ++ ++ @Override ++ public void invalidate() { ++ this.invalid = true; ++ } ++ ++ // use this method internally as it bypasses the valid check ++ public CommandDispatcher getDispatcherInternal() { ++ Preconditions.checkState(this.dispatcher != null, "the dispatcher hasn't been set yet"); ++ return this.dispatcher; ++ } ++ ++ public CommandBuildContext getBuildContext() { ++ Preconditions.checkState(this.buildContext != null, "the build context hasn't been set yet"); ++ return this.buildContext; ++ } ++ ++ @Override ++ public CommandDispatcher getDispatcher() { ++ Preconditions.checkState(!this.invalid && this.dispatcher != null, "cannot access the dispatcher in this context"); ++ return this.dispatcher; ++ } ++ ++ @Override ++ public @Unmodifiable Set register(final LiteralCommandNode node, final @Nullable String description, final Collection aliases) { ++ return this.register(requireNonNull(this.currentContext, "No lifecycle owner context is set").getPluginMeta(), node, description, aliases); ++ } ++ ++ @Override ++ public @Unmodifiable Set register(final PluginMeta pluginMeta, final LiteralCommandNode node, final @Nullable String description, final Collection aliases) { ++ return this.registerWithFlags(pluginMeta, node, description, aliases, Set.of()); ++ } ++ ++ @Override ++ public @Unmodifiable Set registerWithFlags(@NotNull final PluginMeta pluginMeta, @NotNull final LiteralCommandNode node, @org.jetbrains.annotations.Nullable final String description, @NotNull final Collection aliases, @NotNull final Set flags) { ++ final boolean hasFlattenRedirectFlag = flags.contains(CommandRegistrationFlag.FLATTEN_ALIASES); ++ final String identifier = pluginMeta.getName().toLowerCase(Locale.ROOT); ++ final String literal = node.getLiteral(); ++ final PluginCommandNode pluginLiteral = new PluginCommandNode(identifier + ":" + literal, pluginMeta, node, description); // Treat the keyed version of the command as the root ++ ++ final Set registeredLabels = new HashSet<>(aliases.size() * 2 + 2); ++ ++ if (this.registerIntoDispatcher(pluginLiteral, true)) { ++ registeredLabels.add(pluginLiteral.getLiteral()); ++ } ++ if (this.registerRedirect(literal, pluginMeta, pluginLiteral, description, true, hasFlattenRedirectFlag)) { // Plugin commands should override vanilla commands ++ registeredLabels.add(literal); ++ } ++ ++ // Add aliases ++ final List registeredAliases = new ArrayList<>(aliases.size() * 2); ++ for (final String alias : aliases) { ++ if (this.registerRedirect(alias, pluginMeta, pluginLiteral, description, false, hasFlattenRedirectFlag)) { ++ registeredAliases.add(alias); ++ } ++ if (this.registerRedirect(identifier + ":" + alias, pluginMeta, pluginLiteral, description, false, hasFlattenRedirectFlag)) { ++ registeredAliases.add(identifier + ":" + alias); ++ } ++ } ++ ++ if (!registeredAliases.isEmpty()) { ++ pluginLiteral.setAliases(registeredAliases); ++ } ++ ++ registeredLabels.addAll(registeredAliases); ++ return registeredLabels.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(registeredLabels); ++ } ++ ++ private boolean registerRedirect(final String aliasLiteral, final PluginMeta plugin, final PluginCommandNode redirectTo, final @Nullable String description, final boolean override, boolean hasFlattenRedirectFlag) { ++ final LiteralCommandNode redirect; ++ if (redirectTo.getChildren().isEmpty() || hasFlattenRedirectFlag) { ++ redirect = Commands.literal(aliasLiteral) ++ .executes(redirectTo.getCommand()) ++ .requires(redirectTo.getRequirement()) ++ .build(); ++ ++ for (final CommandNode child : redirectTo.getChildren()) { ++ redirect.addChild(child); ++ } ++ } else { ++ redirect = Commands.literal(aliasLiteral) ++ .executes(redirectTo.getCommand()) ++ .redirect(redirectTo) ++ .requires(redirectTo.getRequirement()) ++ .build(); ++ } ++ ++ return this.registerIntoDispatcher(new PluginCommandNode(aliasLiteral, plugin, redirect, description), override); ++ } ++ ++ private boolean registerIntoDispatcher(final PluginCommandNode node, boolean override) { ++ final @Nullable CommandNode existingChild = this.getDispatcher().getRoot().getChild(node.getLiteral()); ++ if (existingChild != null && !(existingChild instanceof PluginCommandNode) && !(existingChild instanceof BukkitCommandNode)) { ++ override = true; // override vanilla commands ++ } ++ if (existingChild == null || override) { // Avoid merging behavior. Maybe something to look into in the future ++ if (override) { ++ this.getDispatcher().getRoot().removeCommand(node.getLiteral()); ++ } ++ this.getDispatcher().getRoot().addChild(node); ++ return true; ++ } ++ ++ return false; ++ } ++ ++ @Override ++ public @Unmodifiable Set register(final String label, final @Nullable String description, final Collection aliases, final BasicCommand basicCommand) { ++ return this.register(requireNonNull(this.currentContext, "No lifecycle owner context is set").getPluginMeta(), label, description, aliases, basicCommand); ++ } ++ ++ @Override ++ public @Unmodifiable Set register(final PluginMeta pluginMeta, final String label, final @Nullable String description, final Collection aliases, final BasicCommand basicCommand) { ++ final LiteralArgumentBuilder builder = Commands.literal(label) ++ .requires(stack -> basicCommand.canUse(stack.getSender())) ++ .then( ++ Commands.argument("args", StringArgumentType.greedyString()) ++ .suggests((context, suggestionsBuilder) -> { ++ String[] args = StringUtils.split(suggestionsBuilder.getRemaining()); ++ if (suggestionsBuilder.getRemaining().endsWith(" ")) { ++ // if there is trailing whitespace, we should add an empty argument to signify ++ // that there may be more, but no characters have been typed yet ++ args = ArrayUtils.add(args, ""); ++ } ++ final SuggestionsBuilder offsetSuggestionsBuilder = suggestionsBuilder.createOffset(suggestionsBuilder.getInput().lastIndexOf(' ') + 1); ++ ++ final Collection suggestions = basicCommand.suggest(context.getSource(), args); ++ suggestions.forEach(offsetSuggestionsBuilder::suggest); ++ return offsetSuggestionsBuilder.buildFuture(); ++ }) ++ .executes((stack) -> { ++ basicCommand.execute(stack.getSource(), StringUtils.split(stack.getArgument("args", String.class), ' ')); ++ return com.mojang.brigadier.Command.SINGLE_SUCCESS; ++ }) ++ ) ++ .executes((stack) -> { ++ basicCommand.execute(stack.getSource(), new String[0]); ++ return com.mojang.brigadier.Command.SINGLE_SUCCESS; ++ }); ++ ++ return this.register(pluginMeta, builder.build(), description, aliases); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/PluginCommandNode.java b/src/main/java/io/papermc/paper/command/brigadier/PluginCommandNode.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3a9f58873b83f10ba354ae4968c4ab0632662439 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/PluginCommandNode.java +@@ -0,0 +1,50 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.mojang.brigadier.tree.CommandNode; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++import java.util.Collections; ++import java.util.List; ++import java.util.Objects; ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import org.bukkit.Bukkit; ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class PluginCommandNode extends LiteralCommandNode { ++ ++ private final PluginMeta plugin; ++ private final String description; ++ private List aliases = Collections.emptyList(); ++ ++ public PluginCommandNode(final @NotNull String literal, final @NotNull PluginMeta plugin, final @NotNull LiteralCommandNode rootLiteral, final @Nullable String description) { ++ super( ++ literal, rootLiteral.getCommand(), rootLiteral.getRequirement(), ++ rootLiteral.getRedirect(), rootLiteral.getRedirectModifier(), rootLiteral.isFork() ++ ); ++ this.plugin = plugin; ++ this.description = description; ++ ++ for (CommandNode argument : rootLiteral.getChildren()) { ++ this.addChild(argument); ++ } ++ } ++ ++ @NotNull ++ public Plugin getPlugin() { ++ return Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(this.plugin.getName())); ++ } ++ ++ @NotNull ++ public String getDescription() { ++ return this.description; ++ } ++ ++ public void setAliases(List aliases) { ++ this.aliases = aliases; ++ } ++ ++ public List getAliases() { ++ return this.aliases; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/PluginVanillaCommandWrapper.java b/src/main/java/io/papermc/paper/command/brigadier/PluginVanillaCommandWrapper.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cf8359af60601d7917e77fd06a00b64992a85953 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/PluginVanillaCommandWrapper.java +@@ -0,0 +1,46 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.mojang.brigadier.tree.CommandNode; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.commands.Commands; ++import org.bukkit.command.Command; ++import org.bukkit.command.PluginIdentifiableCommand; ++import org.bukkit.craftbukkit.command.VanillaCommandWrapper; ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.List; ++ ++// Exists to that /help can show the plugin ++public class PluginVanillaCommandWrapper extends VanillaCommandWrapper implements PluginIdentifiableCommand { ++ ++ private final Plugin plugin; ++ private final List alises; ++ ++ public PluginVanillaCommandWrapper(String name, String description, String usageMessage, List aliases, CommandNode vanillaCommand, Plugin plugin) { ++ super(name, description, usageMessage, aliases, vanillaCommand); ++ this.plugin = plugin; ++ this.alises = aliases; ++ } ++ ++ @Override ++ public @NotNull List getAliases() { ++ return this.alises; ++ } ++ ++ @Override ++ public @NotNull Command setAliases(@NotNull List aliases) { ++ return this; ++ } ++ ++ @Override ++ public @NotNull Plugin getPlugin() { ++ return this.plugin; ++ } ++ ++ // Show in help menu! ++ @Override ++ public boolean isRegistered() { ++ return true; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/ShadowBrigNode.java b/src/main/java/io/papermc/paper/command/brigadier/ShadowBrigNode.java +new file mode 100644 +index 0000000000000000000000000000000000000000..895addef908e09d527e4bc9210599e8827c53807 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/ShadowBrigNode.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.mojang.brigadier.tree.CommandNode; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++ ++import java.util.Collection; ++ ++public class ShadowBrigNode extends LiteralCommandNode { ++ ++ private final CommandNode handle; ++ ++ public ShadowBrigNode(CommandNode node) { ++ super(node.getName(), context -> 0, (s) -> false, node.getRedirect() == null ? null : new ShadowBrigNode(node.getRedirect()), null, node.isFork()); ++ this.handle = node; ++ } ++ ++ @Override ++ public Collection> getChildren() { ++ throw new UnsupportedOperationException("Cannot retrieve children from this node."); ++ } ++ ++ @Override ++ public CommandNode getChild(String name) { ++ throw new UnsupportedOperationException("Cannot retrieve children from this node."); ++ } ++ ++ @Override ++ public void addChild(CommandNode node) { ++ throw new UnsupportedOperationException("Cannot modify children for this node."); ++ } ++ ++ public CommandNode getHandle() { ++ return this.handle; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/argument/SignedMessageResolverImpl.java b/src/main/java/io/papermc/paper/command/brigadier/argument/SignedMessageResolverImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..07a23be2cd7b4592108dee0ae223e71b1d00cec9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/argument/SignedMessageResolverImpl.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.command.brigadier.argument; ++ ++import com.mojang.brigadier.context.CommandContext; ++import com.mojang.brigadier.exceptions.CommandSyntaxException; ++import java.util.concurrent.CompletableFuture; ++import net.kyori.adventure.chat.SignedMessage; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.commands.arguments.MessageArgument; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public record SignedMessageResolverImpl(MessageArgument.Message message) implements SignedMessageResolver { ++ ++ @Override ++ public String content() { ++ return this.message.text(); ++ } ++ ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ @Override ++ public CompletableFuture resolveSignedMessage(final String argumentName, final CommandContext erased) throws CommandSyntaxException { ++ final CompletableFuture future = new CompletableFuture<>(); ++ ++ final MessageArgument.Message response = ((CommandContext) erased).getArgument(argumentName, SignedMessageResolverImpl.class).message; ++ MessageArgument.resolveChatMessage(response, erased, argumentName, (message) -> { ++ future.complete(message.adventureView()); ++ }); ++ return future; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/argument/VanillaArgumentProviderImpl.java b/src/main/java/io/papermc/paper/command/brigadier/argument/VanillaArgumentProviderImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..38fb7d13abfcb55fe4a132b9b27e0c91f8c3d891 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/argument/VanillaArgumentProviderImpl.java +@@ -0,0 +1,366 @@ ++package io.papermc.paper.command.brigadier.argument; ++ ++import com.destroystokyo.paper.profile.CraftPlayerProfile; ++import com.google.common.collect.Collections2; ++import com.google.common.collect.Lists; ++import com.google.common.collect.Range; ++import com.mojang.brigadier.StringReader; ++import com.mojang.brigadier.arguments.ArgumentType; ++import com.mojang.brigadier.context.CommandContext; ++import com.mojang.brigadier.exceptions.CommandSyntaxException; ++import com.mojang.brigadier.suggestion.Suggestions; ++import com.mojang.brigadier.suggestion.SuggestionsBuilder; ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.command.brigadier.PaperCommands; ++import io.papermc.paper.command.brigadier.argument.predicate.ItemStackPredicate; ++import io.papermc.paper.command.brigadier.argument.range.DoubleRangeProvider; ++import io.papermc.paper.command.brigadier.argument.range.IntegerRangeProvider; ++import io.papermc.paper.command.brigadier.argument.range.RangeProvider; ++import io.papermc.paper.command.brigadier.argument.resolvers.BlockPositionResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.FinePositionResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.PlayerProfileListResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.selector.EntitySelectorArgumentResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver; ++import io.papermc.paper.entity.LookAnchor; ++import io.papermc.paper.registry.PaperRegistries; ++import io.papermc.paper.registry.RegistryAccess; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.util.MCUtil; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.List; ++import java.util.UUID; ++import java.util.concurrent.CompletableFuture; ++import java.util.function.Function; ++import net.kyori.adventure.key.Key; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.format.Style; ++import net.minecraft.advancements.critereon.MinMaxBounds; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.commands.arguments.ColorArgument; ++import net.minecraft.commands.arguments.ComponentArgument; ++import net.minecraft.commands.arguments.DimensionArgument; ++import net.minecraft.commands.arguments.EntityAnchorArgument; ++import net.minecraft.commands.arguments.EntityArgument; ++import net.minecraft.commands.arguments.GameModeArgument; ++import net.minecraft.commands.arguments.GameProfileArgument; ++import net.minecraft.commands.arguments.HeightmapTypeArgument; ++import net.minecraft.commands.arguments.MessageArgument; ++import net.minecraft.commands.arguments.ObjectiveCriteriaArgument; ++import net.minecraft.commands.arguments.RangeArgument; ++import net.minecraft.commands.arguments.ResourceArgument; ++import net.minecraft.commands.arguments.ResourceKeyArgument; ++import net.minecraft.commands.arguments.ResourceLocationArgument; ++import net.minecraft.commands.arguments.ScoreboardSlotArgument; ++import net.minecraft.commands.arguments.StyleArgument; ++import net.minecraft.commands.arguments.TemplateMirrorArgument; ++import net.minecraft.commands.arguments.TemplateRotationArgument; ++import net.minecraft.commands.arguments.TimeArgument; ++import net.minecraft.commands.arguments.UuidArgument; ++import net.minecraft.commands.arguments.blocks.BlockStateArgument; ++import net.minecraft.commands.arguments.coordinates.BlockPosArgument; ++import net.minecraft.commands.arguments.coordinates.Vec3Argument; ++import net.minecraft.commands.arguments.item.ItemArgument; ++import net.minecraft.commands.arguments.item.ItemPredicateArgument; ++import net.minecraft.core.BlockPos; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.world.level.Level; ++import net.minecraft.world.phys.Vec3; ++import org.bukkit.GameMode; ++import org.bukkit.HeightMap; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.World; ++import org.bukkit.block.BlockState; ++import org.bukkit.block.structure.Mirror; ++import org.bukkit.block.structure.StructureRotation; ++import org.bukkit.craftbukkit.CraftHeightMap; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.bukkit.craftbukkit.block.CraftBlockStates; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.scoreboard.CraftCriteria; ++import org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.scoreboard.Criteria; ++import org.bukkit.scoreboard.DisplaySlot; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++import static java.util.Objects.requireNonNull; ++ ++@DefaultQualifier(NonNull.class) ++public class VanillaArgumentProviderImpl implements VanillaArgumentProvider { ++ ++ @Override ++ public ArgumentType entity() { ++ return this.wrap(EntityArgument.entity(), (result) -> sourceStack -> { ++ return List.of(result.findSingleEntity((CommandSourceStack) sourceStack).getBukkitEntity()); ++ }); ++ } ++ ++ @Override ++ public ArgumentType entities() { ++ return this.wrap(EntityArgument.entities(), (result) -> sourceStack -> { ++ return Lists.transform(result.findEntities((CommandSourceStack) sourceStack), net.minecraft.world.entity.Entity::getBukkitEntity); ++ }); ++ } ++ ++ @Override ++ public ArgumentType player() { ++ return this.wrap(EntityArgument.player(), (result) -> sourceStack -> { ++ return List.of(result.findSinglePlayer((CommandSourceStack) sourceStack).getBukkitEntity()); ++ }); ++ } ++ ++ @Override ++ public ArgumentType players() { ++ return this.wrap(EntityArgument.players(), (result) -> sourceStack -> { ++ return Lists.transform(result.findPlayers((CommandSourceStack) sourceStack), ServerPlayer::getBukkitEntity); ++ }); ++ } ++ ++ @Override ++ public ArgumentType playerProfiles() { ++ return this.wrap(GameProfileArgument.gameProfile(), result -> { ++ if (result instanceof GameProfileArgument.SelectorResult) { ++ return sourceStack -> Collections.unmodifiableCollection(Collections2.transform(result.getNames((CommandSourceStack) sourceStack), CraftPlayerProfile::new)); ++ } else { ++ return sourceStack -> Collections.unmodifiableCollection(Collections2.transform(result.getNames((CommandSourceStack) sourceStack), CraftPlayerProfile::new)); ++ } ++ }); ++ } ++ ++ @Override ++ public ArgumentType blockPosition() { ++ return this.wrap(BlockPosArgument.blockPos(), (result) -> sourceStack -> { ++ final BlockPos pos = result.getBlockPos((CommandSourceStack) sourceStack); ++ ++ return MCUtil.toPosition(pos); ++ }); ++ } ++ ++ @Override ++ public ArgumentType finePosition(final boolean centerIntegers) { ++ return this.wrap(Vec3Argument.vec3(centerIntegers), (result) -> sourceStack -> { ++ final Vec3 vec3 = result.getPosition((CommandSourceStack) sourceStack); ++ ++ return MCUtil.toPosition(vec3); ++ }); ++ } ++ ++ @Override ++ public ArgumentType blockState() { ++ return this.wrap(BlockStateArgument.block(PaperCommands.INSTANCE.getBuildContext()), (result) -> { ++ return CraftBlockStates.getBlockState(CraftRegistry.getMinecraftRegistry(), BlockPos.ZERO, result.getState(), result.tag); ++ }); ++ } ++ ++ @Override ++ public ArgumentType itemStack() { ++ return this.wrap(ItemArgument.item(PaperCommands.INSTANCE.getBuildContext()), (result) -> { ++ return CraftItemStack.asBukkitCopy(result.createItemStack(1, true)); ++ }); ++ } ++ ++ @Override ++ public ArgumentType itemStackPredicate() { ++ return this.wrap(ItemPredicateArgument.itemPredicate(PaperCommands.INSTANCE.getBuildContext()), type -> itemStack -> type.test(CraftItemStack.asNMSCopy(itemStack))); ++ } ++ ++ @Override ++ public ArgumentType namedColor() { ++ return this.wrap(ColorArgument.color(), result -> ++ requireNonNull( ++ NamedTextColor.namedColor( ++ requireNonNull(result.getColor(), () -> result + " didn't have a color") ++ ), ++ () -> result.getColor() + " didn't map to an adventure named color" ++ ) ++ ); ++ } ++ ++ @Override ++ public ArgumentType component() { ++ return this.wrap(ComponentArgument.textComponent(PaperCommands.INSTANCE.getBuildContext()), PaperAdventure::asAdventure); ++ } ++ ++ @Override ++ public ArgumentType